2009-04-23 19 views
41

Relacionados con mi pregunta anterior: Call repaint from another class in Java?.¿Cómo uso SwingWorker en Java?

Soy nuevo en Java, y he echado un vistazo a algunos tutoriales en SwingWorker, pero no estoy seguro de cómo implementarlo con el código de ejemplo que di en la pregunta anterior.

¿Alguien puede explicar cómo usar SwingWorker en lo que respecta a mi pequeño código o indicarme un tutorial decente, por favor? Lo he buscado pero todavía no estoy seguro de haberlo entendido.

Respuesta

98

En general, SwingWorker se utiliza para realizar tareas de larga ejecución en Swing.

Ejecución de tareas de larga ejecución en el hilo de despacho de eventos (EDT) puede causar la interfaz gráfica de usuario se bloquee, por lo que una de las cosas que se hicieron es utilizar SwingUtilities.invokeLater y invokeAndWait que mantiene la interfaz gráfica de usuario que responde por el cual priorizar la otra AWT eventos antes de ejecutar la tarea deseada (en forma de Runnable). Sin embargo, el problema con SwingUtilities es que no permitió devolver datos del Runnable ejecutado al método original. Esto es lo que SwingWorker fue diseñado para abordar.

El tutorial de Java tiene una sección en SwingWorker.

Aquí hay un ejemplo en el que se usa SwingWorker para ejecutar una tarea que consume mucho tiempo en un subproceso separado, y muestra un cuadro de mensaje un segundo más tarde con la respuesta.

En primer lugar, se hará una clase que se extiende SwingWorker:

class AnswerWorker extends SwingWorker<Integer, Integer> 
{ 
    protected Integer doInBackground() throws Exception 
    { 
     // Do a time-consuming task. 
     Thread.sleep(1000); 
     return 42; 
    } 

    protected void done() 
    { 
     try 
     { 
      JOptionPane.showMessageDialog(f, get()); 
     } 
     catch (Exception e) 
     { 
      e.printStackTrace(); 
     } 
    } 
} 

El tipo de retorno de los métodos doInBackground y get se especifican como el primer tipo de la SwingWorker, y el segundo tipo es del tipo usado para return para los métodos publish y process, que no se usan en este ejemplo.

Luego, para invocar el SwingWorker, se llama al método execute. En este ejemplo, vamos a conectar un ActionListener a un JButton para ejecutar el AnswerWorker:

JButton b = new JButton("Answer!"); 
b.addActionListener(new ActionListener() { 
    public void actionPerformed(ActionEvent e) 
    { 
     new AnswerWorker().execute(); 
    } 
}); 

El botón de arriba se puede añadir a un JFrame, y seleccionada para conseguir un cuadro de mensaje, un segundo después. A continuación se puede utilizar para inicializar la interfaz gráfica de usuario para una aplicación Swing:

private void makeGUI() 
{ 
    final JFrame f = new JFrame(); 
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    f.getContentPane().setLayout(new FlowLayout()); 

    // include: "class AnswerWorker" code here. 
    // include: "JButton" b code here. 

    f.getContentPane().add(b); 
    f.getContentPane().add(new JButton("Nothing")); 
    f.pack(); 
    f.setVisible(true); 
} 

Una vez que se ejecuta la aplicación, habrá dos botones. Uno etiquetado como "¡Respuesta!" y otro "Nada". Cuando uno hace clic en "¡Responder!" botón, nada sucederá al principio, pero al hacer clic en el botón "Nada" funcionará y demostrará que la GUI responde.

Y, un segundo después, el resultado de AnswerWorker aparecerá en el cuadro de mensaje.

+0

No creo que lo que estoy haciendo sea una tarea larga. He pensado en una forma alternativa de tratar este tema, y ​​lo haré en otra pregunta. Gracias – Relequestual

+3

+1 muchas gracias! :) – coder9

+0

@ coder9 De nada :) – coobird

7

de acuerdo:

Ejecución de tareas de larga ejecución en el hilo de despacho de eventos (EDT) puede causar la interfaz gráfica de usuario se bloquee.

no está de acuerdo:

así que una de las cosas que se hicieron es utilizar SwingUtilities.invokeLater y invokeAndWait que mantiene la interfaz gráfica de usuario que responde ..

invokeLater aún se ejecuta el código en el EDT, y puede congelar su UI !! Prueba esto:

SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        Thread.sleep(100000); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
     }); 

Por lo menos, no se puede mover el ratón una vez que haga clic en el botón que activa el actionPerformed con el código de seguridad. ¿Me estoy perdiendo de algo?

+0

Tienes razón. Generalmente se llamará a invokeLater fuera del hilo de envío del evento para ejecutar algo en el hilo de envío del evento, p. una tarea de larga ejecución puede llamar a invocarLater para alterar la pantalla. Esto se debe a que las acciones en los objetos swing deben ocurrir a partir de la cadena de eventos para mantener la seguridad del hilo. – dhorn

Cuestiones relacionadas