Как закрыть приложение 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.