Con la ayuda de las personas en stackoverflow pude obtener el siguiente código de funcionamiento de una cuenta regresiva simple de GUI (que solo muestra una ventana que cuenta en segundos). Mi principal problema con este código es el material invokeLater
.¿Cómo funciona el hilo de envío de eventos?
Por lo que entiendo invokeLater
, envía una tarea a la cadena de distribución de eventos (EDT) y luego la EDT ejecuta esta tarea siempre que "pueda" (lo que sea que eso signifique). ¿Es correcto?
A mi entender, el código funciona así:
En el método
main
invokeLater
utilizamos para mostrar la ventana (showGUI
método). En otras palabras, el código que muestra la ventana se ejecutará en el EDT.En el método
main
también iniciar elcounter
y el contador (por construcción) se ejecuta en otro hilo (lo que no es en el hilo del despacho de eventos). ¿Derecha?La
counter
se ejecuta en una secuencia separada y periódicamente llama aupdateGUI
.updateGUI
se supone que debe actualizar la GUI. Y la GUI está trabajando en el EDT. Por lo tanto,updateGUI
también se debe ejecutar en el EDT. Es la razón por la cual el código paraupdateGUI
está encerrado eninvokeLater
. ¿Está bien?
Lo que no me queda claro es por eso que llamamos el counter
de la EDT. De todos modos, no se ejecuta en el EDT. Comienza inmediatamente, se ejecuta un nuevo hilo y el counter
allí. Entonces, ¿por qué no podemos llamar al counter
en el método principal después del bloque invokeLater
?
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
public class CountdownNew {
static JLabel label;
// Method which defines the appearance of the window.
public static void showGUI() {
JFrame frame = new JFrame("Simple Countdown");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
label = new JLabel("Some Text");
frame.add(label);
frame.pack();
frame.setVisible(true);
}
// Define a new thread in which the countdown is counting down.
public static Thread counter = new Thread() {
public void run() {
for (int i=10; i>0; i=i-1) {
updateGUI(i,label);
try {Thread.sleep(1000);} catch(InterruptedException e) {};
}
}
};
// A method which updates GUI (sets a new value of JLabel).
private static void updateGUI(final int i, final JLabel label) {
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
label.setText("You have " + i + " seconds.");
}
}
);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
showGUI();
counter.start();
}
});
}
}
@Roman aquí hay una discusión más detallada: http://stackoverflow.com/questions/182316/java-swing-libraries-thread-safety – Kiril
@Roman * Nota: * su contador no ** comienza ** en el EDT, comienza en el hilo principal. El contador actualiza la GUI a través del método updateGUI que realiza las actualizaciones en el EDT (debido a la llamada a invocarLater). – Kiril