Search code examples
javaswingdisposejdialog

Java dialog does not dispose


Java noob here. My Swing class that extends JDialog does not dispose when the user presses the Windows Close button - java.exe stays in memory. I've stripped the code right down to this shell, I still get this behaviour.

I took a look at other samples, such as at Basic Java Swing, how to exit and dispose of your application/JFrame
When I commented out the two System.exit(0) lines in that sample code, the class in that sample still disposed correctly. What am I missing to make my class dispose?

import javax.swing.JFrame;
import javax.swing.JDialog;
public class WhyNoDispose extends JDialog{
    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                try {
                    WhyNoDispose frame = new WhyNoDispose("my title");
                    frame.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
                    frame.setVisible(true);
                    //System.exit(0);
                }
                catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
    public WhyNoDispose(String title) {
        super(new JFrame(title), ModalityType.APPLICATION_MODAL);
        pack();
    }
}

Solution

  • You're creating a JFrame and never disposing it here:

    public WhyNoDispose(String title) {
        super(new JFrame(title), ModalityType.APPLICATION_MODAL); // *********
        pack();
    }
    

    So since the JFrame is alive and a GUI has been rendered, the Swing event thread keeps on running.

    If you instead make the JFrame behave so that the program exits on JFrame close, and then explicitly dispose of the JFrame, your program now exits:

    import java.awt.Window;
    
    import javax.swing.JFrame;
    import javax.swing.JDialog;
    
    public class WhyNoDispose extends JDialog {
       public static void main(String[] args) {
          javax.swing.SwingUtilities.invokeLater(new Runnable() {
             public void run() {
                try {
                   WhyNoDispose frame = new WhyNoDispose("my title");
                   frame.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
                   JFrame win = (JFrame) frame.getOwner();
                   win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                   frame.setVisible(true);
                   win.dispose();
                   // System.exit(0);
                } catch (Exception e) {
                   e.printStackTrace();
                }
             }
          });
       }
    
       public WhyNoDispose(String title) {
          super(new JFrame(title), ModalityType.APPLICATION_MODAL);
          pack();
       }
    }
    

    But this is very kludgy code, to say the least -- what if the owning window isn't a JFrame? What if it's null?

    Another solution is to use no JFrame at all, so that when the JDialog is disposed, there's no persisting window left over to make the event thread persist:

    import java.awt.Window;
    
    import javax.swing.JFrame;
    import javax.swing.JDialog;
    
    public class WhyNoDispose extends JDialog {
       public static void main(String[] args) {
          javax.swing.SwingUtilities.invokeLater(new Runnable() {
             public void run() {
                try {
                   WhyNoDispose frame = new WhyNoDispose("my title");
                   frame.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
                   frame.setVisible(true);
                } catch (Exception e) {
                   e.printStackTrace();
                }
             }
          });
       }
    
       public WhyNoDispose(String title) {
          super((JFrame)null, title);
          pack();
       }
    }