高度な検索
Developer Connection
Member Login ログイン | ご入会 ADC連絡先

Technical Q&A QA1187
Prompting the user with MRJQuitHandler


Q: 私のアプリケーションは、ユーザが Command-Q やアプリケーションメニューを使用して終了しようとしたときに、いくつかの終了アクションを実行しなければなりません。このようにするにはどうすればよいのでしょうか?

A: Mac OS X のすべてのアプリケーションは、アプリケーションメニューから「終了」が選択されたとき、および、同等の Command-Q のキー入力があったときに終了することが期待されています。このような要件を満たすために、Mac OS X のグラフィカルな Java アプリケーションにはすべて、この機能が自動的に提供されます。ただしアプリケーションの終了前にコードを実行することもできます。これを行うには、com.apple.mrj.MRJQuitHandler インタフェースを実装するクラスを、アプリケーションに登録する必要があります。そのクラスは handleQuit() メソッドの実装を提供し、MRJApplicationUtils.registerQuitHandler() を使って登録しなければなりません。

変更のなかった作業を保存するにしろ、安全のために単に終了アクションの実行を確認するにしろ、終了の前にユーザに確認を求める場合は、handleQuit() の中からダイアログを開くことができます。ユーザの応答によって、次のどちらかを行う必要があります。

  1. System.exit() を呼び出すことによってアプリケーションを終了する
  2. IllegalStateException を呼び出すことによって終了処理を中止する

Mac OS X の 10.2 より前のバージョンでは 1 つ問題があり、handleQuit() からモーダルダイアログを表示すると、MRJQuitHandlerMRJAboutHandler の両方を登録してた場合にハングします。以前のバージョンでの解決策としては、このダイアログを別のスレッドで表示するという方法があります。10.2 ではこのような問題はないため、この解決策を必要としません(詳しくは下記参照)。

handleQuit() メソッドは、終了前にコードを実行する手段であることに注目してください。handleQuit() の実行が完了すると、アプリケーションは終了するということが前提となります。MRJQuitHandlerjavadocs には、終了を中止するには、IllegalStateException をスローしなければならないと書かれています。これには、上記の解決策のような、別のスレッドで実行中の処理を待つことも含まれます。このように、System.exit() を使用してアプリケーションがいつ終了するかを正確に制御できます。handleQuit() の中でクリーンアップロジックのすべてを実行し、終了を中止したり延期したりする必要がない場合は、IllegalStateException をスローする必要もありません。

下記のコードは、Mac OS X 10.1 および 10.2 で MRJQuitHandler を正しく実装し、終了を確認するためにユーザに安全に確認を求めるサンプルアプリケーションを示しています。下記の例では、終了を中止するために IllegalStateException がスローされていますが、System.exit(0) を呼び出すべきかどうかを決めるために、別のスレッドでユーザが入力できるようになっていることに注目してください。



import javax.swing.*;
import java.awt.*;
import com.apple.mrj.*;

public class MRJHandlerTest extends JFrame implements MRJQuitHandler {

    public MRJHandlerTest() {
        super("TestProject");
        getContentPane().add(new JLabel(
            "<HTML><CENTER>To test the MRJQuitHandler, " +
            "select \"Quit MRJHandlerTest\" " +
            "from the application menu.</CENTER></HTML>"));
        MRJApplicationUtils.registerQuitHandler(this);
    }

    public void handleQuit() {
        // 2868805 の解決策。別のスレッドでモーダルダイアログを表示。
        // この処理は 10.2 では不要だが、あっても問題ない。
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                // ダイアログを表示し、それに応じて振る舞う
                int result = JOptionPane.showConfirmDialog(null,
                    "Do you really want to quit?",
                    "Really Quit?",
                    JOptionPane.YES_NO_OPTION,
                    JOptionPane.QUESTION_MESSAGE);
                if (result == JOptionPane.YES_OPTION) {
                    System.exit(0);
                }
            }
        });

        // 新しいスレッドが実行できるよう IllegalStateException をスロー。10.2 では
        // このスレッドでダイアログを表示する場合は、JOptionPane.NO_OPTION のときにスロー
        throw new IllegalStateException("Quit Pending User Confirmation");
    }

    public static void main(String[] args) {
        new MRJHandlerTest().setVisible(true);
    }
}

リスト 1 MRJQuitHandler の正しい使い方




[2002 年 8 月 13 日]