Q:
私のアプリケーションは、ユーザが Command-Q やアプリケーションメニューを使用して終了しようとしたときに、いくつかの終了アクションを実行しなければなりません。このようにするにはどうすればよいのでしょうか?
A:
Mac OS X のすべてのアプリケーションは、アプリケーションメニューから「終了」が選択されたとき、および、同等の Command-Q のキー入力があったときに終了することが期待されています。このような要件を満たすために、Mac OS X のグラフィカルな Java アプリケーションにはすべて、この機能が自動的に提供されます。ただしアプリケーションの終了前にコードを実行することもできます。これを行うには、com.apple.mrj.MRJQuitHandler インタフェースを実装するクラスを、アプリケーションに登録する必要があります。そのクラスは handleQuit() メソッドの実装を提供し、MRJApplicationUtils.registerQuitHandler() を使って登録しなければなりません。
変更のなかった作業を保存するにしろ、安全のために単に終了アクションの実行を確認するにしろ、終了の前にユーザに確認を求める場合は、handleQuit() の中からダイアログを開くことができます。ユーザの応答によって、次のどちらかを行う必要があります。
System.exit() を呼び出すことによってアプリケーションを終了する
IllegalStateException を呼び出すことによって終了処理を中止する
Mac OS X の 10.2 より前のバージョンでは 1 つ問題があり、handleQuit() からモーダルダイアログを表示すると、MRJQuitHandler と MRJAboutHandler の両方を登録してた場合にハングします。以前のバージョンでの解決策としては、このダイアログを別のスレッドで表示するという方法があります。10.2 ではこのような問題はないため、この解決策を必要としません(詳しくは下記参照)。
handleQuit() メソッドは、終了前にコードを実行する手段であることに注目してください。handleQuit() の実行が完了すると、アプリケーションは終了するということが前提となります。MRJQuitHandler の javadocs には、終了を中止するには、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 日]
|