102

What is the proper way to terminate a Swing application from the code, and what are the pitfalls?

I'd tried to close my application automatically after a timer fires. But just calling dispose() on the JFrame didn't do the trick - the window vanished but the application did not terminate. However when closing the window with the close button, the application does terminate. What should I do?

palacsint
  • 28,416
  • 10
  • 82
  • 109
Dr. Hans-Peter Störr
  • 25,298
  • 30
  • 102
  • 139

9 Answers9

113

Your JFrame default close action can be set to "DISPOSE_ON_CLOSE" instead of EXIT_ON_CLOSE (why people keep using EXIT_ON_CLOSE is beyond me).

If you have any undisposed windows or non-daemon threads, your application will not terminate. This should be considered a error (and solving it with System.exit is a very bad idea).

The most common culprits are java.util.Timer and a custom Thread you've created. Both should be set to daemon or must be explicitly killed.

If you want to check for all active frames, you can use Frame.getFrames(). If all Windows/Frames are disposed of, then use a debugger to check for any non-daemon threads that are still running.

James Schek
  • 17,844
  • 7
  • 51
  • 64
  • In my case I discovered with the debugger that I had a Swingworker still active. I called its cancel(true) method in the WindowClose Eventlistener and the program terminates now. Thanks! – Dr. Hans-Peter Störr Jul 09 '09 at 13:05
  • Note that you may have to call dispose on each frame, and typically that is "enough" (though setting the default close action to EXIT_ON_CLOSE is probably not a bad idea either). – rogerdpack Nov 18 '10 at 23:21
  • What if you have one window opening another, but not disposing itself, so that you can use it for a `back` window? If the second window is then closed and you use `DISPOSE_ON_CLOSE` the programme doesn't terminate because the first window is still "undisposed"... is there a way to solve that _without_ using `DISPOSE_ON_CLOSE`? – Svend Hansen Aug 14 '12 at 16:05
  • First window should add itself to as a listener to the second window and take appropriate action. – James Schek Aug 17 '12 at 04:45
  • This response suggests the exact opposite of Bizorke's answer. Which one is correct? (when I test with a simple application, both seem to work ...) – O. R. Mapper May 07 '13 at 08:29
  • 3
    Using EXIT_ON_CLOSE will forcibly terminate the application. If you need to take action before the program exits (such as saving working data), then you have to tap into the JVM event handlers instead of just using the normal swing event handlers. Both will "work", but the EXIT_ON_CLOSE will cause problems for more complex apps. – James Schek May 11 '13 at 06:32
  • An example in support of graceful shutdown: I needed to ensure my finally block was executed so network connections were closed gracefully. This would not happen with a System.exit call (EXIT_ON_CLOSE). – Ryan Jun 24 '14 at 19:32
  • 2015 and the default option (when none is explicitly set) is still 'HIDE_ON_CLOSE'. Just why? Disposing the instance is a much better option for a default behavior... – v1n1akabozo Nov 07 '15 at 15:06
38

I guess a EXIT_ON_CLOSE

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

before System.exit(0) is better since you can write a Window Listener to make some cleaning operations before actually leaving the app.

That window listener allows you to defined:

public void windowClosing(WindowEvent e) {
    displayMessage("WindowListener method called: windowClosing.");
    //A pause so user can see the message before
    //the window actually closes.
    ActionListener task = new ActionListener() {
        boolean alreadyDisposed = false;
        public void actionPerformed(ActionEvent e) {
            if (frame.isDisplayable()) {
                alreadyDisposed = true;
                frame.dispose();
            }
        }
    };
    Timer timer = new Timer(500, task); //fire every half second
    timer.setInitialDelay(2000);        //first delay 2 seconds
    timer.setRepeats(false);
    timer.start();
}

public void windowClosed(WindowEvent e) {
    //This will only be seen on standard output.
    displayMessage("WindowListener method called: windowClosed.");
}
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
18

Try:

System.exit(0);

Crude, but effective.

Daniel Spiewak
  • 54,515
  • 14
  • 108
  • 120
  • Unfortunately this is too crude for me. I want the window closing events to be processed for some cleanup actions. OK, I could do a System.exit with a SwingUtils.invokeLater, but I'd rather do the proper thing. – Dr. Hans-Peter Störr Nov 03 '08 at 08:06
  • 6
    System.exit(0) isn't just crude, it's evil. Check all frames, call dispose. If that fails, run a debugger and see what non-daemon threads are still alive. – James Schek Nov 03 '08 at 17:10
  • There's been plenty of bugs even within the JDK that leave the process about. So +1 to exit(), but you might want to disable it in debug builds. – Tom Hawtin - tackline Feb 25 '09 at 14:26
11

May be the safe way is something like:

    private JButton btnExit;
    ...
    btnExit = new JButton("Quit");      
    btnExit.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e){
            Container frame = btnExit.getParent();
            do 
                frame = frame.getParent(); 
            while (!(frame instanceof JFrame));                                      
            ((JFrame) frame).dispose();
        }
    });
Hubert Kario
  • 21,314
  • 3
  • 24
  • 44
Kachwahed
  • 542
  • 7
  • 17
9

The following program includes code that will terminate a program lacking extraneous threads without explicitly calling System.exit(). In order to apply this example to applications using threads/listeners/timers/etc, one need only insert cleanup code requesting (and, if applicable, awaiting) their termination before the WindowEvent is manually initiated within actionPerformed().

For those who wish to copy/paste code capable of running exactly as shown, a slightly-ugly but otherwise irrelevant main method is included at the end.

public class CloseExample extends JFrame implements ActionListener {

    private JButton turnOffButton;

    private void addStuff() {
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        turnOffButton = new JButton("Exit");
        turnOffButton.addActionListener(this);
        this.add(turnOffButton);
    }

    public void actionPerformed(ActionEvent quitEvent) {
        /* Iterate through and close all timers, threads, etc here */
        this.processWindowEvent(
                new WindowEvent(
                      this, WindowEvent.WINDOW_CLOSING));
    }

    public CloseExample() {
        super("Close Me!");
        addStuff();
    }

    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                CloseExample cTW = new CloseExample();
                cTW.setSize(200, 100);
                cTW.setLocation(300,300);
                cTW.setVisible(true);
            }
        });
    }
}
afsantos
  • 5,178
  • 4
  • 30
  • 54
Eric Sadler
  • 1
  • 1
  • 1
4

If I understand you correctly you want to close the application even if the user did not click on the close button. You will need to register WindowEvents maybe with addWindowListener() or enableEvents() whichever suits your needs better.

You can then invoke the event with a call to processWindowEvent(). Here is a sample code that will create a JFrame, wait 5 seconds and close the JFrame without user interaction.

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class ClosingFrame extends JFrame implements WindowListener{

public ClosingFrame(){
    super("A Frame");
    setSize(400, 400);
            //in case the user closes the window
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setVisible(true);
            //enables Window Events on this Component
            this.addWindowListener(this);

            //start a timer
    Thread t = new Timer();
            t.start();
    }

public void windowOpened(WindowEvent e){}
public void windowClosing(WindowEvent e){}

    //the event that we are interested in
public void windowClosed(WindowEvent e){
    System.exit(0);
}

public void windowIconified(WindowEvent e){}
public void windowDeiconified(WindowEvent e){}
public void windowActivated(WindowEvent e){}
public void windowDeactivated(WindowEvent e){}

    //a simple timer 
    class Timer extends Thread{
           int time = 10;
           public void run(){
     while(time-- > 0){
       System.out.println("Still Waiting:" + time);
               try{
                 sleep(500);                     
               }catch(InterruptedException e){}
             }
             System.out.println("About to close");
    //close the frame
            ClosingFrame.this.processWindowEvent(
                 new WindowEvent(
                       ClosingFrame.this, WindowEvent.WINDOW_CLOSED));
           }
    }

    //instantiate the Frame
public static void main(String args[]){
          new ClosingFrame();
    }

}

As you can see, the processWindowEvent() method causes the WindowClosed event to be fired where you have an oportunity to do some clean up code if you require before closing the application.

Vincent Ramdhanie
  • 102,349
  • 23
  • 137
  • 192
2

Take a look at the Oracle Documentation.

Starting from JDK 1.4 an Application terminates if:

  • There are no displayable AWT or Swing components.
  • There are no native events in the native event queue.
  • There are no AWT events in java EventQueues.

Cornercases:

The document states that some packages create displayable components without releasing them.A program which calls Toolkit.getDefaultToolkit() won't terminate. is among others given as an example.

Also other Processes can keep AWT alive when they, for what ever reason, are sending events into the native event queue.

Also I noticed that on some Systems it takes a coupple of seconds before the Application actually terminates.

Reiner Lange
  • 69
  • 1
  • 5
0

I think, the idea is here the WindowListener - you can add any code there that you'd like to run before the thing shuts down

Tamas Rev
  • 7,008
  • 5
  • 32
  • 49
0

In response to other comments, DISPOSE_ON_CLOSE does not seem to properly exit the application - it only destroys the window, but the application will continue running. If you want to terminate the application use EXIT_ON_CLOSE.

JSideris
  • 5,101
  • 3
  • 32
  • 50