JFrameの終了をキャンセル
Total: 52905, Today: 2, Yesterday: 0
Posted by aterai at
Last-modified:
Summary
JFrameを閉じる前に、本当に終了してよいか、終了をキャンセルするかなどを確認するダイアログを表示します。
Screenshot

Advertisement
Source Code Examples
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 = sampleDocumentSaveMethod();
// 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, KotlinDescription
上記のサンプルでは、アプリケーションの終了時に、ドキュメントが保存されているかどうかで処理を変更するために、ウィンドウイベントを受け取るためのリスナーを設定しています。
WindowListener#windowClosing(WindowEvent e)- システムメニューでウィンドウを閉じようとしたときに呼び出されるリスナーのメソッド
OSがWindowsならAlt+F4キーを押す- タイトルバー左上にあるアイコンをクリックしポップアップメニューで閉じるを選択
- タイトルバー右上の
×ボタンをクリック JButtonやJMenuなどをクリックした時に対象となるframeのwindowClosingを呼び出したい場合は、frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));
frame.dispose();ではこのメソッドは呼び出されない
- システムメニューでウィンドウを閉じようとしたときに呼び出されるリスナーのメソッド
WindowListener#windowClosed(WindowEvent e)frame.dispose()でウィンドウがクローズされたときに呼び出されるリスナーのメソッドwindowClosingの後自動的にwindowClosedが呼び出されるのはWindowConstants.DISPOSE_ON_CLOSEの場合のみ- このサンプルでは
Web Startから起動しても終了できるようにframe.dispose()すれば必ず呼び出されるこのメソッド中でSystem.exit(0);を使いJVMごとシャットダウンしている
JFrame#setDefaultCloseOperationメソッドでタイトルバー右上の×ボタンをクリック(デフォルトの終了処理)し、windowClosingが呼ばれた後(このためwindowClosing中で変更しても有効)の動作を設定可能- これらの動作については
JFrame#processWindowEvent(WindowEvent)のソースを参照
- これらの動作については
WindowConstants.DO_NOTHING_ON_CLOSEwindowClosingが呼ばれた後になにもしない(終了しない)return;と同じ- このサンプルでは
WindowConstants.DO_NOTHING_ON_CLOSEを設定しているが、システムメニューでウィンドウを閉じても、下のexitボタンと同じ処理になるようにwindowClosingの中で終了処理を行うmaybeExit()メソッドを呼び出し、そこでドキュメントの保存状態によってframe.dispose();を呼んでいる
WindowConstants.HIDE_ON_CLOSEwindowClosingが呼ばれた後でウィンドウは非表示になるsetVisible(false);と同じ- 初期値
WindowConstants.DISPOSE_ON_CLOSEwindowClosingが呼ばれた後でウィンドウは破棄されるdispose();と同じdispose()されるのでこの後windowClosedが呼び出される
WindowConstants.EXIT_ON_CLOSEwindowClosingが呼ばれた後でJVMがシャットダウンされるSystem.exit(0);と同じdispose()されないのでwindowClosedは呼び出されない
- テキストが変更された場合、タイトル文字列の先頭にアスタリスクを付けることで保存状態の可視化と保持を行っている
- ドキュメントに文字列が追加されたとき、ソース側から
firePropertyChangeなどでリスナーに変更をイベントで報告 - リスナー側ではこのイベントを受け
JFrameのタイトルを変更