Swing/WindowClosing のバックアップ(No.22)
- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- 現在との差分 - 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の終了をキャンセル tags: [JFrame, WindowListener] author: aterai pubdate: 2004-08-09 description: JFrameを閉じる前に、本当に終了してよいか、終了をキャンセルするかなどを確認するダイアログを表示します。
概要
JFrame
を閉じる前に、本当に終了してよいか、終了をキャンセルするかなどを確認するダイアログを表示します。
Screenshot
![Swing/WindowClosing screenshot](https://ateraimemo.com/swing/windowclosing/screenshot.png)
Advertisement
サンプルコード
class SaveHandler extends WindowAdapter implements DocumentListener, ActionListener {
//public static final String ASTERISK_TITLEBAR = "unsaved";
public static final String CMD_SAVE = "save";
public static final String CMD_EXIT = "exit";
private final JFrame frame;
private final String title;
private final List<JComponent> list = new ArrayList<>();
public SaveHandler(JFrame frame) {
super();
this.frame = frame;
this.title = frame.getTitle();
}
//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
}
//ActionListener
@Override public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if (CMD_EXIT.equals(cmd)) {
maybeExit();
} else if (CMD_SAVE.equals(cmd)) {
fireUnsavedFlagChangeEvent(false);
}
}
//DocumentListener
@Override public void insertUpdate(DocumentEvent e) {
fireUnsavedFlagChangeEvent(true);
}
@Override public void removeUpdate(DocumentEvent e) {
fireUnsavedFlagChangeEvent(true);
}
@Override public void changedUpdate(DocumentEvent e) {
/* not needed */
}
private void maybeExit() {
if (title.equals(frame.getTitle())) {
System.out.println(
"The document has already been saved, exit without doing anything.");
frame.dispose();
return;
}
Toolkit.getDefaultToolkit().beep();
Object[] options = {"Save", "Discard", "Cancel"};
int retValue = JOptionPane.showOptionDialog(
frame, "<html>Save: Exit & Save Changes<br>"
+ "Discard: Exit & Discard Changes<br>Cancel: Continue</html>",
"Exit Options", JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.INFORMATION_MESSAGE, null, options, options[0]);
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");
}
}
public void addEnabledFlagComponent(JComponent c) {
list.add(c);
}
public void removeEnabledFlagComponent(JComponent c) {
list.remove(c);
}
private void fireUnsavedFlagChangeEvent(boolean unsaved) {
frame.setTitle(String.format("%s%s", unsaved ? "* " : "", title));
for (JComponent c : list) {
c.setEnabled(unsaved);
}
}
}
View in GitHub: Java, Kotlin解説
上記のサンプルでは、アプリケーションの終了時に、ドキュメントが保存されているかどうかで処理を変更するために、ウィンドウイベントを受け取るためのリスナーを設定しています。
WindowAdapter#windowClosing(WindowEvent e)
- システムメニューでウィンドウを閉じようとしたときに呼び出されるリスナーのメソッド
OS
がWindows
なら、Alt+F4キーを押す- タイトルバー左上にあるアイコンをクリックし、ポップアップメニューで閉じるを選択
- タイトルバー右上の×ボタンをクリック
JButton
やJMenu
などをクリックした時に、対象となるframe
のwindowClosing
を呼び出したい場合は、frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));
frame.dispose();
では、このメソッドは呼び出されない
- システムメニューでウィンドウを閉じようとしたときに呼び出されるリスナーのメソッド
WindowAdapter#windowClosed(WindowEvent e)
frame.dispose()
で、ウィンドウがクローズされたときに呼び出されるリスナーのメソッドwindowClosing
の後、自動的にwindowClosed
が呼び出されるのは、WindowConstants.DISPOSE_ON_CLOSE
の場合のみ- このサンプルでは、
Web Start
から起動しても終了できるように、frame.dispose()
すれば必ず呼び出されるこのメソッド中でSystem.exit(0);
を使い、JVM
ごとシャットダウンしているWeb Start
でシャットダウンする必要性については、When DISPOSE_ON_CLOSE met WebStartを参考に
JFrame#setDefaultCloseOperation
メソッドで、タイトルバー右上の×ボタンをクリック(=デフォルトの終了処理)し、windowClosing
が呼ばれた後(このためwindowClosing
中で変更しても有効)の動作を設定できます(これらの動作については、JFrame#processWindowEvent(WindowEvent)
のソースを参照)。
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
のタイトルを変更