Swing/WindowClosing のバックアップ(No.9)
- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- 現在との差分 - Visual を表示
- ソース を表示
- Swing/WindowClosing へ行く。
- 1 (2007-10-08 (月) 16:11:56)
- 2 (2007-10-08 (月) 23:07:09)
- 3 (2008-04-22 (火) 19:05:14)
- 4 (2008-04-22 (火) 21:30:57)
- 5 (2008-04-23 (水) 01:11:16)
- 6 (2008-04-23 (水) 13:21:09)
- 7 (2008-04-23 (水) 15:28:42)
- 8 (2008-04-23 (水) 21:28:02)
- 9 (2008-04-24 (木) 12:31:06)
- 10 (2008-04-26 (土) 00:16:44)
- 11 (2008-05-07 (水) 18:35:31)
- 12 (2008-05-08 (木) 18:57:20)
- 13 (2008-05-09 (金) 12:34:44)
- 14 (2008-05-19 (月) 18:34:50)
- 15 (2008-11-25 (火) 11:25:18)
- 16 (2011-03-04 (金) 14:49:54)
- 17 (2011-03-17 (木) 22:27:27)
- 18 (2012-05-08 (火) 11:24:44)
- 19 (2013-04-11 (木) 21:58:54)
- 20 (2013-07-26 (金) 01:01:21)
- 21 (2014-09-30 (火) 01:16:09)
- 22 (2015-11-05 (木) 03:21:40)
- 23 (2015-12-21 (月) 00:38:59)
- 24 (2016-06-01 (水) 20:48:49)
- 25 (2016-08-12 (金) 15:41:24)
- 26 (2017-09-29 (金) 18:00:48)
- 27 (2018-02-24 (土) 19:46:52)
- 28 (2020-03-03 (火) 18:01:19)
- 29 (2021-08-17 (火) 20:08:30)
- 30 (2024-02-15 (木) 20:17:21)
TITLE:JFrameの終了をキャンセル
JFrameの終了をキャンセル
Posted by terai at 2004-08-09
概要
JFrameを閉じる前に、本当に終了してよいか、終了をキャンセルするかなどを確認するダイアログを表示します。
- &jnlp;
- &jar;
- &zip;
#screenshot
サンプルコード
public static final String ASTERISK_TITLEBAR = "unsaved";
private final JTextArea textarea = new JTextArea();
private final JButton saveButton = new JButton("save");
private final JFrame frame;
private final String title;
public MainPanel(final JFrame frame) {
super(new BorderLayout());
this.frame = frame;
this.title = frame.getTitle();
frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
if(ASTERISK_TITLEBAR.equals(e.getPropertyName())) {
Boolean flg = (Boolean)e.getNewValue();
frame.setTitle((flg?"* ":"")+title);
}
}
});
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.out.println("windowClosing");
maybeExit();
}
@Override
public void windowClosed(WindowEvent e) {
System.out.println("windowClosed");
System.exit(0); // webstart
}
});
textarea.setText("Test Test Test");
textarea.getDocument().addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent e) {
fireUnsavedFlagChangeEvent(true);
}
public void removeUpdate(DocumentEvent e) {
fireUnsavedFlagChangeEvent(true);
}
public void changedUpdate(DocumentEvent e) {}
});
saveButton.setEnabled(false);
saveButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
System.out.println("Save(dummy)");
fireUnsavedFlagChangeEvent(false);
}
});
add(new JScrollPane(textarea));
Box box = Box.createHorizontalBox();
box.add(Box.createHorizontalGlue());
box.add(new JButton(new AbstractAction("exit") {
public void actionPerformed(ActionEvent e) {
System.out.println("exit button");
maybeExit();
}
}));
box.add(Box.createHorizontalStrut(5));
box.add(saveButton);
add(box, BorderLayout.SOUTH);
setPreferredSize(new Dimension(320, 240));
}
private void maybeExit() {
if(title.equals(frame.getTitle())) {
System.out.println("The document has already been saved,"+
" exit without doing anything.");
frame.dispose();
return;
}
java.awt.Toolkit.getDefaultToolkit().beep();
String[] obj = {"unsaved documents", "Do you really want to exit?"};
int retValue = JOptionPane.showConfirmDialog(frame, obj, "Select an Option",
JOptionPane.YES_NO_CANCEL_OPTION);
if(retValue==JOptionPane.YES_OPTION) {
System.out.println("exit");
//boolean ret = dummyDocumentSaveMethod();
//if(ret) { //saved and exit
// frame.dispose();
//}else{ //error and cancel exit
// return;
//}
frame.dispose();
}else if(retValue==JOptionPane.NO_OPTION) {
System.out.println("Exit without save");
frame.dispose();
}else if(retValue==JOptionPane.CANCEL_OPTION) {
System.out.println("Cancel exit");
}
}
private void fireUnsavedFlagChangeEvent(boolean unsaved) {
if(unsaved) {
saveButton.setEnabled(true);
firePropertyChange(ASTERISK_TITLEBAR, Boolean.FALSE, Boolean.TRUE);
}else{
saveButton.setEnabled(false);
firePropertyChange(ASTERISK_TITLEBAR, Boolean.TRUE, Boolean.FALSE);
}
}
解説
上記のサンプルでは、アプリケーションの終了時に、ドキュメントが保存されているかどうかで処理を変更するために、ウィンドウイベントを受け取るためのリスナーを設定しています。
- public void windowClosing(WindowEvent e)
- システムメニューでウィンドウを閉じようとしたときに呼び出されるリスナーのメソッド
- タイトルバー左上クリックなどでポップアップするメニューで閉じるを選択
- タイトルバー右上の×ボタンをクリック
- Windowsなら、Alt+F4キーを押す
- JButtonやJMenuなどから呼び出したい場合
frame.getToolkit().getSystemEventQueue().postEvent( new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));
- frame.dispose();では、このメソッドは呼び出されない
- システムメニューでウィンドウを閉じようとしたときに呼び出されるリスナーのメソッド
- public void windowClosed(WindowEvent e)
- frame.dispose() で、ウィンドウがクローズされたときに呼び出されるリスナーのメソッド
- WindowConstants.DISPOSE_ON_CLOSEの場合のみ、windowClosingの後に、windowClosedが呼び出される
- このサンプルでは、webstartから起動しても終了できるように、frame.dispose()の後で必ず呼び出されるこのメソッド中でSystem.exit(0);を使い、JVMをシャットダウンしている
- webstartでシャットダウンする必要性については、When DISPOSE_ON_CLOSE met WebStartを参考に
JFrame#setDefaultCloseOperation メソッドで、タイトルバー右上の×ボタンをクリック(=デフォルトの終了処理)し、windowClosingが呼ばれた後(このためwindowClosing中で変更しても有効)の動作を設定できます*1。
- WindowConstants.DO_NOTHING_ON_CLOSE
- windowClosingが呼ばれた後になにもしない(終了しない)
- return; と同じ
- このサンプルでは、WindowConstants.DO_NOTHING_ON_CLOSE を設定しているが、システムメニューでウィンドウを閉じても、下のexitボタンと同じ処理になるように、windowClosingの中で終了処理を行うメソッド(maybeExit())を呼び出し、そこでドキュメントの保存状態によってframe.dispose();を呼んでいる
- WindowConstants.HIDE_ON_CLOSE
- windowClosingが呼ばれた後でウインドウは非表示になる
- setVisible(false); と同じ
- 初期値
- WindowConstants.DISPOSE_ON_CLOSE
- windowClosingが呼ばれた後でウインドウは破棄される
- dispose(); と同じ
- dispose()されるので、windowClosedが呼び出される
- WindowConstants.EXIT_ON_CLOSE
- windowClosingが呼ばれた後でJVMがシャットダウンれさる
- System.exit(0); と同じ
- dispose()されないので、windowClosedは呼び出されない
テキストが変更された場合、タイトル文字列の先頭にアスタリスクを付けることで、保存状態の可視化と保持を行っています。
- ドキュメントに文字列が追加されたとき、ソース側からfirePropertyChangeなどで、リスナーに変更をイベントで報告
- リスナー側ではこのイベントを受け、JFrameのタイトルを変更
参考リンク
コメント
- 私は以前 この終了をキャンセルするかどうかなどを確認するダイアログを作成したことがあります。あなたのソースコードは 参考のかいがあると思います。でも ひとつの問題があるんですけど、textareaに入力した文字列を削除する場合は JFrameのタイトルが変化されていません、どうですか? -- そうがい?
- こんばんは。「"123"->"12345"(45追加)->"123"(45削除)」と追加、削除をして元の状態に戻っても、タイトルが変化しないのは、仕様です。比較のコストが大きくなってしまいそうで嫌なので避けています。 -- terai
- 変更をアスタリスクに変更、コードの構成を変更、スクリーンショット更新 -- terai