showoptiondialog - Cómo cerrar una aplicación Java Swing desde el código
joptionpane showoptiondialog (9)
¿Cuál es la forma correcta de terminar una aplicación Swing del código y cuáles son las dificultades?
Intenté cerrar mi aplicación automáticamente después de que se dispara el temporizador. Pero el solo hecho de invocar a dispose()
en el JFrame
no JFrame
el problema: la ventana desapareció pero la aplicación no finalizó. Sin embargo, al cerrar la ventana con el botón Cerrar, la aplicación finaliza. ¿Que debería hacer?
Creo que la idea es aquí WindowListener: puedes agregar allí cualquier código que quieras ejecutar antes de que la cosa se apague
Eche un vistazo a la Documentación de Oracle .
A partir de JDK 1.4, una aplicación finaliza si:
- No hay componentes desplegables AWT o Swing.
- No hay eventos nativos en la cola de eventos nativos.
- No hay eventos AWT en Java EventQueues.
Cajitas en esquina:
El documento establece que algunos paquetes crean componentes visualizables sin liberarlos. Un programa que llama a Toolkit.getDefaultToolkit () no terminará. es entre otros dado como un ejemplo.
También otros procesos pueden mantener a AWT con vida cuando, por alguna razón, envían eventos a la cola de eventos nativos.
También noté que en algunos Sistemas toma un par de segundos antes de que la Aplicación realmente termine.
El siguiente programa incluye código que terminará un programa que carece de hilos extraños sin llamar explícitamente a System.exit (). Para aplicar este ejemplo a aplicaciones que usan threads / listeners / timers / etc, basta con insertar el código de limpieza solicitando (y, si corresponde, esperar) su terminación antes de que WindowEvent se inicie manualmente dentro de actionPerformed ().
Para aquellos que desean copiar / pegar código capaz de ejecutarse exactamente como se muestra, al final se incluye un método principal levemente feo pero irrelevante.
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);
}
});
}
}
En respuesta a otros comentarios, DISPOSE_ON_CLOSE no parece salir correctamente de la aplicación; solo destruye la ventana, pero la aplicación continuará ejecutándose. Si desea terminar la aplicación, use EXIT_ON_CLOSE.
La acción de cierre predeterminada de JFrame se puede establecer en " DISPOSE_ON_CLOSE
" en lugar de EXIT_ON_CLOSE
(la razón por la que la gente sigue usando EXIT_ON_CLOSE está más allá de mí).
Si tiene ventanas sin oposición o hilos que no son daemon, su aplicación no terminará. Esto debería considerarse un error (y resolverlo con System.exit es una muy mala idea).
Los culpables más comunes son java.util.Timer y un Thread personalizado que ha creado. Ambos deben establecerse en daemon o deben eliminarse explícitamente.
Si desea verificar todos los marcos activos, puede usar Frame.getFrames()
. Si se eliminan todas las ventanas / marcos, utilice un depurador para comprobar si hay subprocesos que no son demonios que aún se están ejecutando.
Puede ser la manera segura es algo así como:
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();
}
});
Si lo entiendo correctamente, quiere cerrar la aplicación incluso si el usuario no hizo clic en el botón de cerrar. Tendrá que registrar WindowEvents tal vez con addWindowListener () o enableEvents () el que mejor se adapte a sus necesidades.
A continuación, puede invocar el evento con una llamada a processWindowEvent (). Aquí hay un código de muestra que creará un JFrame, esperará 5 segundos y cerrará el JFrame sin interacción del usuario.
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();
}
}
Como puede ver, el método processWindowEvent () hace que se active el evento WindowClosed donde tiene la oportunidad de hacer un código de limpieza si lo necesita antes de cerrar la aplicación.
Supongo que un EXIT_ON_CLOSE
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
antes System.exit(0)
es mejor, ya que puede escribir un Oyente de Ventana para realizar algunas operaciones de limpieza antes de salir de la aplicación.
Ese oyente de ventana le permite definir:
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.");
}
Tratar:
System.exit(0);
Crudo, pero efectivo.