tags:

views:

17240

answers:

8

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?

+3  A: 

Try:

System.exit(0);

Crude, but effective.

Daniel Spiewak
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.
hstoerr
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
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
+7  A: 

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
+3  A: 

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
windowClosed should call dispose() not System.exit(0).
James Schek
+10  A: 

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
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!
hstoerr
A: 

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
A: 

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);
        }
    });
}

}

Eric Sadler
A: 

another way is:

try {

  Thread.sleep(2000) //or any other number

} catch (InterruptedException e) {

  e.printStackTrace();

  throw e;

}

System.exit(0);

It works!

Unknown
What possible good can come of sleeping like that?
I82Much
What do you mean?
Unknown
And who changed the vote to -1?
Unknown
A: 

Actually, here is a better way of shutting a window down from a button:

public void actionPerformed(ActionEvent event) {
    String command = event.getActionCommand();
    if (command.equals("Close Window")) {
        closewindow();
    }
}
void closewindow() {
    System.exit(0);
}
Unknown