Как закрыть приложение Java Swing из кода

Каков правильный способ прервать приложение Swing из кода и каковы подводные камни?

Я попытался закрыть свое приложение автоматически после срабатывания таймера. Но просто вызов dispose() на JFrame не сделал трюк - окно исчезло, но приложение не закончилось. Однако при закрытии окна с помощью кнопки закрытия приложение завершается. Что мне делать?

Ответ 1

Ваше действие закрытия по умолчанию JFrame может быть установлено на "DISPOSE_ON_CLOSE" вместо EXIT_ON_CLOSE (почему люди продолжают использовать EXIT_ON_CLOSE вне меня).

Если у вас есть неизолированные окна или не-демона, ваше приложение не будет завершено. Это следует рассматривать как ошибку (и решить ее с помощью System.exit - очень плохая идея).

Наиболее распространенными виновниками являются java.util.Timer и пользовательский поток, который вы создали. Оба должны быть установлены на демон или должны быть явно убиты.

Если вы хотите проверить все активные фреймы, вы можете использовать Frame.getFrames(). Если все Windows/Frames удалены, используйте отладчик, чтобы проверить какие-либо потоки не-демона, которые все еще запущены.

Ответ 2

Я думаю, EXIT_ON_CLOSE

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

до System.exit(0) лучше, так как вы можете написать Window Listener, чтобы выполнить некоторые операции очистки, прежде чем покинуть приложение.

Этот прослушиватель окон позволяет вам определить:

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

Ответ 3

Try:

System.exit(0);

Сырой, но эффективный.

Ответ 4

Может быть, безопасный способ - это что-то вроде:

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

Ответ 5

Следующая программа включает в себя код, который завершит работу программы с отсутствием посторонних потоков без явного вызова System.exit(). Чтобы применить этот пример к приложениям, используя потоки/слушатели/таймеры/и т.д., Нужно только вставлять код очистки, запрашивающий (и, если применимо, ожидающий) их завершение до того, как WindowEvent инициируется вручную в actionPerformed().

Для тех, кто хочет скопировать/вставить код, способный работать точно так, как показано, в конце включен слегка уродливый, но в противном случае нерелевантный основной метод.

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

Ответ 6

Если вы правильно поняли, что хотите закрыть приложение, даже если пользователь не нажал кнопку закрытия. Вам нужно будет зарегистрировать WindowEvents, возможно, с помощью addWindowListener() или enableEvents() в зависимости от ваших потребностей.

Затем вы можете вызвать событие с вызовом processWindowEvent(). Вот пример кода, который создаст JFrame, подождать 5 секунд и закроет JFrame без взаимодействия с пользователем.

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

}

Как вы можете видеть, метод processWindowEvent() заставляет событие WindowClosed запускаться, когда у вас есть возможность сделать некоторый очищающий код, если вам нужно до закрытия приложения.

Ответ 7

Взгляните на Документацию Oracle.

Начиная с JDK 1.4 приложение завершается, если:

  • Нет отображаемых компонентов AWT или Swing.
  • В собственной очереди событий нет встроенных событий.
  • В java EventQueues нет событий AWT.

Cornercases:

В документе указано, что некоторые пакеты создают отображаемые компоненты, не отпуская их. Программа, которая вызывает Toolkit.getDefaultToolkit(), не будет завершена. среди прочих, приведенных в качестве примера.

Кроме того, другие процессы могут сохранять AWT в живых, когда они по какой-либо причине отправляют события в очередь собственных событий.

Также я заметил, что на некоторых системах он занимает несколько секунд до того, как приложение фактически завершится.

Ответ 8

Я думаю, идея здесь WindowListener - вы можете добавить туда любой код, который вы хотите запустить до того, как вещь выключится

Ответ 9

В ответ на другие комментарии DISPOSE_ON_CLOSE, похоже, не корректно выходит из приложения - он только уничтожает окно, но приложение будет продолжать работать. Если вы хотите прервать использование приложения EXIT_ON_CLOSE.