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?

Jason S
  • 184,598
  • 164
  • 608
  • 970

6 Answers6

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();
            }
        });
    }
}
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • 3
    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." (http://download.oracle.com/javase/6/docs/api/javax/swing/JDialog.html#setDefaultCloseOperation%28int%29) I never realized that was a useful side effect of disposing a window. – Jason S Apr 04 '11 at 15:41
  • +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. – camickr Apr 04 '11 at 15:52
  • 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) – Ingo Apr 05 '11 at 17:56
  • @Ingo: I think the _may_ caveat refers to [JLS §12.8 Program Exit](http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.8), 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 @camickr meant exit in the normal course of events. – trashgod Apr 05 '11 at 19:40
  • @trashgod - 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. – Ingo Apr 06 '11 at 08:26
  • "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. – Jason S Apr 06 '11 at 12:48
  • @trashgod Sorry, but the link in your post seems doesn't work for me. – Tony Jun 11 '14 at 03:31
  • @Tony: Updated to Java SE 8. – trashgod Jun 11 '14 at 10:00
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);
camickr
  • 321,443
  • 19
  • 166
  • 288
  • The VM may or may not exit, depending on the code that created that frame. – Ingo Apr 04 '11 at 15:34
  • +1 This also works for closing the dialog itself in isolation. – trashgod Apr 04 '11 at 15:47
  • @Ingo, actually this is not dependent on the code that created the frame. It bypasses the setDefaultCloseOperation(...) and does the dispose directly. – camickr Apr 04 '11 at 15:51
  • @camickr: You mean it is not possible to do something after the main window has closed? – Ingo Apr 04 '11 at 16:36
  • @Ingo, I'm not sure what you are asking. If you dispose the last frame then the VM will exit. – camickr Apr 04 '11 at 17:25
  • 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. – Ingo Apr 05 '11 at 09:16
  • @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. – camickr Apr 05 '11 at 15:45
  • 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! – Ingo Apr 05 '11 at 15:56
2

Use

this.dispose();

It should work.

The Guy with The Hat
  • 10,836
  • 8
  • 57
  • 75
A.K.
  • 2,284
  • 3
  • 26
  • 35
  • 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. – Torsten Sep 19 '18 at 13:55
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)

martin
  • 980
  • 1
  • 13
  • 28
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.

Manoj
  • 5,542
  • 9
  • 54
  • 80
0

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

krookedking
  • 2,203
  • 20
  • 21