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


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

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

9 86

9 ответов:

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

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

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

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

Я думаю, a EXIT_ON_CLOSE

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

до System.exit(0) лучше, так как можно написать Слушателя Окна чтобы сделать некоторые операции очистки перед фактическим выходом из приложения.

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

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

попробуй:

System.exit(0);

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

может быть безопасным способом является что-то вроде:

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

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

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

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

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

посмотри Документация Oracle.

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

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

Cornercases:

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

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

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

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

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