An Old SwingWorker Example
Home ] Up ] Old SwingWorker ] [ An Old SwingWorker Example ] New SwingWorker ] A New SwingWorker Example ]

 

 

Note that, for the following examples, I have taken the SwingWorker class and "cleaned it up" somewhat.  In particular, I have added it to the package oldSwingWorker, because the use of the default package is to be discouraged.  If you want to take a look at my version of the SwingWorker class, you can download it from here.  

Note that my version of the SwingWorker class probably does not include some of the fixes that have been applied since I downloaded it.  You should plan on using the new version of SwingWorker instead.

Here's an example of the use of my "old" version of the SwingWorker class.

package oldSwingWorker;

/**
 * This is an interface for a multi-step progress responder.
 */
public interface MultiStepProgress
{
   public void stepComplete(int stepNo);

   public void finished();

   public void unexpectedAction(String actionName);
}
package oldSwingWorker;

/**
 * This is a multi-step worker thread
 */
public class MultiStepWorker extends SwingWorker
{
  public MultiStepWorker(MultiStepProgress responder)
  {
    m_responder = responder;
  }
  
  public int getTotalSteps()
  {
    return m_stepCount;
  }
  
  public Object construct()
  {
    try
    {
      for (int step = 1; step <= m_stepCount; step++)
      {
        if (Thread.interrupted())
        {
          throw new InterruptedException();
        }
        Thread.sleep(50);  // Represents a step
        m_responder.stepComplete(step);
      }
    }
    catch (InterruptedException ie)
    {
      m_responder.unexpectedAction("Interrupted");
    }
    return null;   // No interesting value computed in this case
  }
  
  public void finished()
  {
    m_responder.finished();  // Invoke the responder's finished method
  }
  
  private MultiStepProgress m_responder;
  private static int m_stepCount = 500;
}
package oldSwingWorker;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.EventQueue;
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.JProgressBar;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;

/**
 * This is a frame which shows how we can provide visual responses from each of
 * multiple steps of time-consuming work in a background worker thread.
 */

public class MultiStepExample extends JFrame
{
  /**
   * Constructor
   */
  public MultiStepExample()
  {
    setTitle("Multi-step Work Example");
    setSize(200, 200);
    Container outerPanel = getContentPane();
    outerPanel.setLayout( new BorderLayout() );
    // Button panel goes to the top
    outerPanel.add( new ButtonPanel(), BorderLayout.NORTH );
    
    // Progress panel goes below it.
    JPanel progressPanel = new JPanel( new BorderLayout() );
    // Progress bar at top of progress panel
    m_progress.setStringPainted(true);
    m_progress.setBackground(Color.white);
    m_progress.setForeground(Color.blue);
    progressPanel.add( m_progress, BorderLayout.NORTH );
    // Progress status label below it
    m_statusLabel.setOpaque(true);
    m_statusLabel.setBackground(Color.white);
    m_statusLabel.setForeground(Color.black);
    progressPanel.add( m_statusLabel, BorderLayout.SOUTH );
    outerPanel.add( progressPanel, BorderLayout.CENTER );
    
    pack();
  }
  
  private JProgressBar m_progress = new JProgressBar();
  private JLabel m_statusLabel = 
    new JLabel("To start work, click on Start button", SwingConstants.CENTER);
  
  class ButtonPanel extends JPanel implements ActionListener, MultiStepProgress
  {
    ButtonPanel()
    {
      m_startButton.addActionListener(this);
      m_startButton.setBackground(Color.green);  // For "GO"
      m_startButton.setForeground(Color.black);
      add(m_startButton);
      
      m_cancelButton.addActionListener( new ActionListener()
      {
        public void actionPerformed(ActionEvent ev)
        {
          m_workerThread.interrupt();  // Causes an interrupt of thread
        }
      }
      );
      m_cancelButton.setEnabled(false);  // Disable until appropriate
      m_cancelButton.setBackground(Color.red);  // For "STOP"
      m_cancelButton.setForeground(Color.black);
      add(m_cancelButton);
    }
    
    public void actionPerformed(ActionEvent ev)
    {
      m_abnormal = false;
      m_startButton.setEnabled(false); // Prevent multiple worker threads
      m_cancelButton.setEnabled(true); // Enable cancellation
      m_statusLabel.setBackground(Color.white);
      m_statusLabel.setText("Working...");
      m_workerThread = new MultiStepWorker(this);
      m_progress.setMinimum( 0 );
      m_progress.setMaximum( m_workerThread.getTotalSteps() );
      m_workerThread.start();
    }
    
    public void stepComplete(final int stepNo)
    {
      Runnable runnable = new Runnable()
      {
        public void run()
        {
          m_progress.setValue(stepNo);
        }
      };
      SwingUtilities.invokeLater(runnable);
    }
    
    public void finished()
    {
      if (!m_abnormal)
      {
        m_statusLabel.setText("Work complete.");
      }
      m_startButton.setEnabled(true);
      m_cancelButton.setEnabled(false);
      m_workerThread = null;  // Release the thread reference
    }
    
    public void unexpectedAction(String actionName)
    {
      m_statusLabel.setBackground(Color.red);
      m_statusLabel.setText(actionName);
      m_abnormal = true;
    }
    
    private JButton m_startButton = new JButton("Start");
    private JButton m_cancelButton = new JButton("Cancel");
    private MultiStepWorker m_workerThread;
    private boolean m_abnormal = false;
  }
  
  public static void main(String[] args)
  {
    EventQueue.invokeLater( new Runnable()
      {
        public void run()
        {
          MultiStepExample frame = new MultiStepExample();
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.pack();
          frame.setVisible(true);
        }
      }
    );
  }
}

Notice:

  • The use of an interface, MultiStepProgress,
  • The use of a MultiStepWorker class, which extends the SwingWorker class, and accepts an instance of a class that implements the MultiStepProgress interface..
  • The fact that the ButtonPanel implements the MultiStepProgress interface, and a reference to it is passed into the MultiStepWorker thread.

This helps to separate the GUI details from the worker thread, and vice versa -- separation of form and function, which is a very important design approach.

Try It!

Here is an applet that invokes the above code when you click on its "Start" button
(It requires the use of Java 6.0, so be prepared for errors if your browser plug-in is at a lower version number):

Your browser does not have Java support. Please install the Java Plug-in. After you've brought up the JFrame, click on the "Start" button, and see what actually happens! 

Results

The program should:
  1. Change the contents of the label to "Working..."
  2. Start visible progress in the progress bar
  3. Disable the Start button, and enable the Cancel button

You can:

  • Let it continue until the end, in which case the label will change to say "Work complete"

or:

  • Click on the Cancel button, which will cause the work to stop prematurely;  the label will change to "Interrupted", and its background color will change to red.

In either case, the Cancel button should be disabled, and the Start button should be re-enabled.

 

The page was last updated February 19, 2008