Java Swing How to - Handle time consuming task in SwingWorker and block user interaction








Question

We would like to know how to handle time consuming task in SwingWorker and block user interaction.

Answer

import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
//from w ww.  j  a  v a  2  s. com
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;

public class Main extends JPanel {
  JButton startButton;
  JTextArea taskOutput;

  public Main() {
    super(new BorderLayout());
    JProgressBar progressBar = new JProgressBar(0, 100);
    progressBar.setValue(0);
    progressBar.setStringPainted(true);

    taskOutput = new JTextArea(5, 20);
    taskOutput.setEditable(false);

    startButton = new JButton("Start");
    startButton.setActionCommand("start");
    startButton.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent ae) {
        startButton.setEnabled(false);
        setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));

        final Task task = new Task();
        task.addPropertyChangeListener(new PropertyChangeListener() {
          @Override
          public void propertyChange(PropertyChangeEvent pce) {
            if ("progress".equals(pce.getPropertyName())) {
              int progress = (Integer) pce.getNewValue();
              progressBar.setValue(progress);
              taskOutput.append(String.format("Completed %d%% of task.\n",
                  task.getProgress()));
            }
          }
        });
        task.execute();
      }
    });

    JPanel panel = new JPanel();
    panel.add(startButton);
    panel.add(progressBar);

    add(panel, BorderLayout.PAGE_START);
    add(new JScrollPane(taskOutput), BorderLayout.CENTER);

  }
  public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    JPanel progressBarPanel = new Main();
    frame.add(progressBarPanel);

    frame.pack();
    frame.setVisible(true);
  }

  private class Task extends SwingWorker<Void, Void> {
    @Override
    public Void doInBackground() {
      int progress = 0;
      setProgress(0);
      while (progress < 100) {
        try {
          Thread.sleep(1000);
        } catch (Exception ignore) {
        }
        progress += 1;
        setProgress(Math.min(progress, 100));
      }
      return null;
    }

    @Override
    public void done() {
      startButton.setEnabled(true);
      setCursor(null);
      taskOutput.append("Done!\n");
    }
  }
}