2011-02-07 27 views
8

¿Cuál es la forma correcta de actualizar la interfaz de usuario después de realizar algunas operaciones en Swing?Swing, cómo actualizar correctamente la interfaz de usuario

Por ejemplo, después de hacer clic en un botón, se invoca un método que puede ser casi instantáneo o demorar algunos segundos. De hecho, toda la lógica de aplicación se realiza de forma remota a través de un servicio web, por lo que es normal esperar un poco para que la aplicación responda.

Mi manejador de sucesos de un botón puede parecerse a éstas:

myButton.addActionListener(new java.awt.event.ActionListener() { 
    public void actionPerformed(java.awt.event.ActionEvent evt) { 
     //callWebService(); 
     //do stuff 
     //updateUI(); // <----- repaint? revalidate? what? 
    } 
}); 

Mi actual aplicación llama al método updateUI la que llaman internamente validate() y volver a pintar() para el componente de matriz que mantiene la interfaz de usuario. Esto funciona, pero a veces puedo ver la pantalla parpadear. ¿Lo estoy haciendo mal? Hay una mejor manera de hacerlo?

+0

http://en.wikipedia.org/wiki/SwingWorker – qwerty

+0

Según tengo entendido, esta pregunta se trata de actualizar la IU después de hacer algo, no de hacer cosas en otro hilo para mantener la IU receptiva. Todavía no entiendo por qué se mencionó el tiempo de ejecución del método en la pregunta. –

+0

Mencioné el tiempo de ejecución porque parece que Swing se comporta un poco diferente cuando intenta cargar componentes y la carga lleva demasiado tiempo, por lo tanto, tal vez sea necesario volver a dibujar la pantalla. – Hectoret

Respuesta

0

Normalmente, no debería tener que hacer nada: si usa los métodos de componentes oscilantes, o los métodos de su modelo, se activan los eventos necesarios y la GUI debe actualizarse automáticamente.

Este no será el caso si define sus propios modelos (y se olvide de disparar los eventos necesarios, pero entonces se trata de un error en sus modelos, y debe ser fijado allí.

+0

Entonces, si invoco, por ejemplo, el método JSpinner.setValue() en el hilo de procesamiento de eventos de la GUI, ¿debería actualizar la UI automáticamente? Recuerdo que no lo hacía a veces en una de mis aplicaciones. Si moviera la ventana o hiciera algo que lo invalidaría (como oscurecerlo temporalmente en alguna otra ventana), entonces se actualizaría. ¿Eso era un error en el JRE? –

+0

Sí, ti debe actualizar la GUI automáticamente (una vez que no hay nada más que hacer en el hilo de envío del evento (EDT)), y si se asegura de llamar al método en el EDT. No puedo decir por qué no funcionó en una aplicación, pero debería hacerlo. –

1

Tome la carrera de larga tarea a un hilo diferente. Enviar eventos al AWT Event Dispatch Thread (EDT) para actualizar la GUI con java.awt.EventQueue.invokeLater.

5

La manera correcta sería usar SwingWorker, pero si quiere hacerlo manualmente, tendrá para implementar el siguiente patrón:

@Override public void actionPerformed(java.awt.event.ActionEvent evt) { 
    new Thread() { 
    @Override public void run() { 
     //callWebService(); 
     //do stuff 
     SwingUtilities.invokeLater(new Runnable(){ 
     @Override public void run() { 
      //updateUI(); // <----- repaint? revalidate? what? 
     } 
     }); 
    } 
    }.start(); 
} 

Para la pregunta de volver a pintar/revalidar, normalmente llame al revalidate() y luego al repaint(). esto es, por supuesto, solo válido para el componente que dibuja manualmente. Para los componentes que reutiliza, simplemente llame a sus métodos de cambio de valor.

+0

¿Por qué SwingWorker no está utilizando la forma "correcta" de hacer esto? Proporciona una interfaz agradable y fácil de usar que maneja todas las cosas de devolución de llamada por usted, y proporciona una manera fácil de actualizar la interfaz de usuario cuando se completa la tarea. – berry120

+2

@berry, pensé que "sin SwingWorker, que es la manera correcta de hacer esto" se entiende como "usar Swing Worker es la manera correcta, pero si quieres hacerlo sin usarlo ..." –

+1

Ah, ya veo, aunque un poco ambiguo, ¡creo que se puede tomar de cualquier manera! – berry120

4

que haría uso personal SwingWorker para esto, a pesar de algunos de los otros comentarios/respuestas:

  • A pesar del hecho de mantener la interfaz de usuario sensible no es parte de la pregunta original, es una buena práctica para hacer esto de todos modos (no puedo pensar en una sola buena razón para bloquear el EDT con un procesamiento largo.)
  • Proporciona un método done() que se puede implementar que se ejecutará en el EDT de forma predeterminada cuando se complete la tarea, guardando la necesidad de cerrar las cosas manualmente en invokeLater()
  • Es más ex Tensible, proporcionando el marco para permitir que la información como el progreso se agregue fácilmente más tarde si así lo desea.

He visto mucho odio de SwingWorker en general recientemente, y no entiendo por qué. Es una clase extensible y bien diseñada específicamente para fines como este que funciona bien. Sí, podría envolver las cosas en hilos y ejecutarlas y hacer que envuelvan otros métodos en invokeLater(), pero ¿por qué reinventar la rueda cuando hay una mejor disponible de forma gratuita?

Cuestiones relacionadas