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

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

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


person Community    schedule 03.11.2008    source источник
comment
Пожалуйста, опубликуйте фрагмент кода вашего таймера.   -  person James Schek    schedule 03.11.2008


Ответы (9)


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

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

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

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

person James Schek    schedule 03.11.2008
comment
В моем случае я обнаружил с помощью отладчика, что у меня все еще активен Swingworker. Я вызвал его метод cancel(true) в WindowClose Eventlistener, и теперь программа завершается. Спасибо! - person Hans-Peter Störr; 09.07.2009
comment
Обратите внимание, что вам, возможно, придется вызывать dispose для каждого кадра, и обычно этого достаточно (хотя установка действия закрытия по умолчанию на EXIT_ON_CLOSE, вероятно, тоже неплохая идея). - person rogerdpack; 19.11.2010
comment
Что, если у вас есть одно окно, открывающее другое, но не удаляющее себя, так что вы можете использовать его для back окна? Если затем закрыть второе окно и использовать DISPOSE_ON_CLOSE, программа не завершится, потому что первое окно все еще не размещено... есть ли способ решить эту проблему без использования DISPOSE_ON_CLOSE? - person Svend Hansen; 14.08.2012
comment
Первое окно должно добавить себя в качестве слушателя ко второму окну и предпринять соответствующие действия. - person James Schek; 17.08.2012
comment
Этот ответ предполагает полную противоположность ответа Бизорке. Который правильный? (когда я тестирую простое приложение, оба работают...) - person O. R. Mapper; 07.05.2013
comment
Использование EXIT_ON_CLOSE принудительно завершит работу приложения. Если вам нужно выполнить действие перед выходом из программы (например, сохранить рабочие данные), вам нужно подключиться к обработчикам событий JVM, а не просто использовать обычные обработчики событий Swing. Оба будут работать, но EXIT_ON_CLOSE вызовет проблемы для более сложных приложений. - person James Schek; 11.05.2013
comment
Пример в поддержку изящного завершения работы: мне нужно было убедиться, что мой блок finally выполняется, чтобы сетевые соединения закрывались корректно. Этого не произойдет с вызовом System.exit (EXIT_ON_CLOSE). - person Ryan; 24.06.2014
comment
2015, а параметр по умолчанию (если ни один из них не задан явно) по-прежнему «HIDE_ON_CLOSE». Просто почему? Утилизация экземпляра - гораздо лучший вариант для поведения по умолчанию... - person v1n1akabozo; 07.11.2015

Я предполагаю, что 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.");
}
person VonC    schedule 03.11.2008

Пытаться:

System.exit(0);

Грубо, но эффективно.

person Daniel Spiewak    schedule 03.11.2008
comment
К сожалению, это слишком грубо для меня. Я хочу, чтобы события закрытия окна обрабатывались для некоторых действий по очистке. Хорошо, я мог бы сделать System.exit с SwingUtils.invokeLater, но я бы предпочел сделать правильно. - person Hans-Peter Störr; 03.11.2008
comment
System.exit(0) не просто груб, это зло. Проверьте все кадры, вызовите dispose. Если это не удается, запустите отладчик и посмотрите, какие потоки, не являющиеся демонами, все еще живы. - person James Schek; 03.11.2008
comment
Даже в JDK было много ошибок, из-за которых процесс прерывался. Итак, +1 к выходу(), но вы можете отключить его в отладочных сборках. - person Tom Hawtin - tackline; 25.02.2009

Может быть, безопасный способ выглядит примерно так:

    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();
        }
    });
person Community    schedule 24.06.2011
comment
Довольно плохой стиль называть переменную Frame с большой буквы, точно так же, как имя класса… - person Jean-Philippe Pellet; 05.11.2012
comment
Большое спасибо! Это один из лучших способов! - person rzaaeeff; 20.02.2016

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

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

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);
            }
        });
    }
}
person Community    schedule 06.04.2010

Если я вас правильно понял, вы хотите закрыть приложение, даже если пользователь не нажал кнопку закрытия. Вам нужно будет зарегистрировать 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, где у вас есть возможность выполнить некоторую очистку кода перед закрытием приложения.

person Vincent Ramdhanie    schedule 03.11.2008
comment
windowClosed должен вызывать dispose(), а не System.exit(0). - person James Schek; 03.11.2008

Ознакомьтесь с документацией Oracle. .

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

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

Угловые шкафы:

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

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

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

person Community    schedule 25.09.2013

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

person Community    schedule 18.01.2010

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

person Community    schedule 16.08.2011
comment
Этот ответ предполагает полную противоположность ответу Джеймса Шека. Который правильный? (когда я тестирую простое приложение, оба работают...) - person O. R. Mapper; 07.05.2013
comment
Не могу вспомнить, как я это проверял сейчас. - person JSideris; 08.05.2013