Using a Worker Thread
Home ] Up ] The Problem ] Update Swing Only From The EDT ] Avoid Too Much Work in The EDT ] Providing Visual Feedback ] [ Using a Worker Thread ] Using SwingWorker ]

 

 

If we want to separate out the work from the way it is invoked ("separation of form vs. function"), we can create ourselves a worker thread which can perform the necessary long-running work:

package workerThread;

/**
 * This is an interface for a status responder.
 */
public interface StatusResponder
{
  /**
   * Called when the work has started
   */
  public void started();
  
  /**
   * Called when all the work is complete
   */
  public void done();
}
package workerThread;

/**
 * This class is a worker thread which can be used to perform 
 * time-consuming work outside of the event dispatch thread.
 */

public class WorkerThread extends Thread
{
  public WorkerThread(StatusResponder responder)
  {
    m_responder = responder;
  }
  
  /**
   * The run method for the worker thread, 
   * where the work gets done.
   */
  public void run()
  {
    m_responder.started();
    try
    {
      Thread.sleep(10000); // represents a long operation of some kind.
    }
    catch (InterruptedException ie)
    {
      ie.printStackTrace();
    }
    m_responder.done();
  }
  
  private StatusResponder m_responder;
}
package workerThread;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;

/**
 * This is a frame which solves the problems associated with trying to
 * do large amounts of work from within the Event Dispatch Thread.
 * It uses a separate WorkerThread class.
 */

public class WorkerThreadExample extends JFrame
{
  //Construct the applet
  public WorkerThreadExample()
  {
    setTitle("Worker Thread Example");
    setSize(200, 200);
    Container contentPane = getContentPane();
    contentPane.setLayout(new BorderLayout());
    contentPane.add( new ButtonPanel(), BorderLayout.CENTER );
    contentPane.add(m_progressLabel, BorderLayout.SOUTH);
  }
  
  class ButtonPanel extends JPanel implements ActionListener
  {
    ButtonPanel()
    {
      setBackground(Color.blue);
      m_clickMeButton.addActionListener(this);
      add(m_clickMeButton);
      
      m_nowClickMeButton.addActionListener( new ActionListener()
        {
          public void actionPerformed(ActionEvent ev)
          {
            ButtonPanel.this.setBackground(Color.yellow);
          }
        }
      );
      m_nowClickMeButton.setEnabled(false);  // Disable for now
      add(m_nowClickMeButton);
    }
    
    public void actionPerformed(ActionEvent ev)
    {
      setBackground(Color.red);
      m_nowClickMeButton.setEnabled(true);
      new WorkerThread( new Responder() ).start();
    }
  }
  
  public static void main(String[] args)
  {
    WorkerThreadExample frame = new WorkerThreadExample();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
  }
  
  /**
   * Inner responder class
   */
  class Responder implements StatusResponder
  {
    public void started()
    {
      setStatus(false, "Started work...");
    }
    
    public void done()
    {
      setStatus(true, "Done!");
    }
    
    private void setStatus(final boolean enable, final String text)
    {
      SwingUtilities.invokeLater( new Runnable()
        {
          public void run()
          {
            m_progressLabel.setText(text);
            m_clickMeButton.setEnabled(enable);
          }
        }
      );
    }
  }
  
  private JButton m_clickMeButton = new JButton("Click me!");
  private JButton m_nowClickMeButton = new JButton("Now try to click me!");
  private JLabel m_progressLabel = new JLabel(" ", SwingConstants.CENTER);
}

The only change we made was to move the work out into the separate WorkerThread's run() method.

Note that we have provided a StatusResponder to provide some user feedback.

Try It!

Here is an applet that invokes the above code when you click on its "Start" button:

Your browser does not have Java support. Please install the Java Plug-in. Again, after you've brought the JFrame up, try clicking on the "Click me!" button, and see what actually happens!

 

The page was last updated February 19, 2008