What is the right action to take upon closing windows in java/swing?
Asked Answered
R

6

14

I just wrote this test code in my CustomUIPanel class:

public static void main(String[] args) {
    final JDialog dialog = CustomUIPanel.createDialog(null, 
       CustomUIPanel.selectFile());
    dialog.addWindowListener(new WindowAdapter() {
        @Override public void windowClosing(WindowEvent e) {
            System.exit(0);
        }
    });
}

It works correctly if CustomUIPanel.main() is the program's entry point, but it makes me wonder something: what if another class called CustomUIPanel.main() for testing? Then my call to System.exit(0) is incorrect.

Is there a way to tell the Swing event dispatch thread to exit automatically if there are no top-level windows?

If not, what's the right thing for a JDialog/JFrame to do upon closing if the goal is for the program to exit when all the top level windows are closed?

Reathareave answered 4/4, 2011 at 15:0 Comment(0)
Y
17

You can use the setDefaultCloseOperation() method of JDialog, specifying DISPOSE_ON_CLOSE:

setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);

See also 12.8 Program Exit.

Addendum: Incorporating @camickr's helpful answer, this example exits when either the window is closed or the close button is pressed.

import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.WindowEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;

/** @see http://stackoverflow.com/questions/5540354 */
public class DialogClose extends JDialog {

    public DialogClose() {
        this.setLayout(new GridLayout(0, 1));
        this.add(new JLabel("Dialog close test.", JLabel.CENTER));
        this.add(new JButton(new AbstractAction("Close") {

            @Override
            public void actionPerformed(ActionEvent e) {
                DialogClose.this.setVisible(false);
                DialogClose.this.dispatchEvent(new WindowEvent(
                    DialogClose.this, WindowEvent.WINDOW_CLOSING));
            }
        }));
    }

    private void display() {
        this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        this.pack();
        this.setLocationRelativeTo(null);
        this.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new DialogClose().display();
            }
        });
    }
}
Yeo answered 4/4, 2011 at 15:32 Comment(8)
Aha! you are correct, the key documentation here is "Note: When the last displayable window within the Java virtual machine (VM) is disposed of, the VM may terminate." (download.oracle.com/javase/6/docs/api/javax/swing/…) I never realized that was a useful side effect of disposing a window.Reathareave
+1, I knew dispose() on the last frame would exit the VM. It is now confirmed that dispose() on the last dialog will do the same.Shafer
No. Please read "the VM MAY terminate" (namely, if creation of the GUI and the GUI working threads were the last action in the main thread, which is, admittedly, often the case)Mab
@Ingo: I think the may caveat refers to JLS §12.8 Program Exit, cited above. The event queue thread terminates when the last top-level container closes, but a daemon thread or an uncaught EDT exception may thwart a clean exit. I suspect that @Shafer meant exit in the normal course of events.Yeo
@Yeo - Sure, what I want to point out is that the GUI threads are just threads, and the GUI objects are just objects. There is no magic in the VM that causes it to terminate just because the GUI thread terminates. There could be other active threads that are not yet terminated and are no daemon threads.Mab
"There could be other active threads that are not yet terminated" -- but I'm in charge of those other threads; I'm not in charge of the Swing event dispatch thread.Reathareave
@Yeo Sorry, but the link in your post seems doesn't work for me.Phenomenology
@Tony: Updated to Java SE 8.Yeo
S
3

Not sure about when using a JDialog.

But when using a JFrame you should use frame.dispose(). If the frame is the last open frame then the VM will exit.

Note a dialog does not have an EXIT_ON_CLOSE option since it should not generally exit the VM.

When closing the dialog you could always get the dialogs parent frame. Then you could dispatch an event to the frame to tell it to close itself. Something like:

WindowEvent windowClosing = new WindowEvent(frame, WindowEvent.WINDOW_CLOSING);
//Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(windowClosing);
frame.dispatchEvent(windowClosing);
Shafer answered 4/4, 2011 at 15:18 Comment(8)
The VM may or may not exit, depending on the code that created that frame.Mab
+1 This also works for closing the dialog itself in isolation.Yeo
@Ingo, actually this is not dependent on the code that created the frame. It bypasses the setDefaultCloseOperation(...) and does the dispose directly.Shafer
@camickr: You mean it is not possible to do something after the main window has closed?Mab
@Ingo, I'm not sure what you are asking. If you dispose the last frame then the VM will exit.Shafer
Why should this be so? Just because in most programs the start of the GUI is the last action in main? You could as well state: After "Hello World" is printed on the console, the VM will exit. It will indeed in most Helloworld programs. But it may also be otherwise.Mab
@Ingo, I still have no idea what you are talking about. The question is about showing a dialog. Once the dialog is shown the EDT is started so the JVM will stay active. If you "hide" the dialog the JVM will still be active. If you "dispose" the dialog then the JVM will automatically stop.Shafer
The JVM exits in 3 cases as far as I know: 1) main() returns 2) System.exit() is called 3) an exception causes main to end abruptly. I challenge you: Please show me where it is written that the JVM must stop when a dialog/frame is dispose()d!Mab
F
2

Use

this.dispose();

It should work.

Fagoting answered 26/6, 2015 at 12:35 Comment(1)
This worked for me. I have a program that uses a JDialog to query a password. After attaining it, the process kept on running, even though dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE) and the main was done already. Adding dispose after the password retrieval finally and successfully ended the process.Allinclusive
I
0

Well,

You could use a JFrame instead. JDialog is supposed to be used as popup of an application that runs in an JFrame to catch the users attention and to pause the main application. If the JFrame is closed, you can call System.exit(0)

Indecipherable answered 4/4, 2011 at 15:15 Comment(2)
But if I have two or three JFrames acting independently, then System.exit() is an inappropriate action.Reathareave
Yes, then you should set the default close operation instead.Indecipherable
M
0

dialog has a getParent() method, which I guess, is set to null in your case here CustomUIPanel.createDialog(null,

you can use that to exit conditionally.

Mainmast answered 4/4, 2011 at 15:17 Comment(0)
S
0

Here is what I would recommend : dialog.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

Silhouette answered 4/4, 2011 at 15:31 Comment(1)
This throws java.lang.IllegalArgumentException at runtime.Yeo

© 2022 - 2024 — McMap. All rights reserved.