Stop/cancel SwingWorker thread?
I'm trying to find out how to stop a SwingWorker thread from running when I press a button. I have been looking around and I'm having some trouble working out how to do this. At the moment this is what I have:
new MySwingWorkerClass(args).execute();
I'm then creating a button which I want to use in order to stop the thread:
button = new JButton("Stop");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
// Stop the swing worker thread
}
});
I have already looked around in search of an answer, so far I have managed to find the cancel method. I don't understand how to use this to stop my swing worker though. I tried the following but it didn't work:
SwingWorker.cancel(true);
Solution 1:
You need to keep a reference to your SwingWorker, then you use that reference to cancel the worker thread.
MySwingWorker myWorker = new MySwingWorkerClass(args).execute();
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
// Stop the swing worker thread
myWorker.cancel(true);
}
});
Here is a full example:
public class WorkerDemo extends JFrame {
private boolean isStarted = false;
private JLabel counterLabel = new JLabel("Not started");
private Worker worker = new Worker();
private JButton startButton = new JButton(new AbstractAction("Start") {
@Override
public void actionPerformed(ActionEvent arg0) {
if(!isStarted) {
worker.execute();
isStarted = false;
}
}
});
private JButton stopButton = new JButton(new AbstractAction("Stop") {
@Override
public void actionPerformed(ActionEvent arg0) {
worker.cancel(true);
}
});
public WorkerDemo() {
add(startButton, BorderLayout.WEST);
add(counterLabel, BorderLayout.CENTER);
add(stopButton, BorderLayout.EAST);
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
class Worker extends SwingWorker<Void, Integer> {
int counter = 0;
@Override
protected Void doInBackground() throws Exception {
while(true) {
counter++;
publish(counter);
Thread.sleep(60);
}
}
@Override
protected void process(List<Integer> chunk) {
// get last result
Integer counterChunk = chunk.get(chunk.size()-1);
counterLabel.setText(counterChunk.toString());
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new WorkerDemo();
}
});
}
}
Solution 2:
You need to periodically check its cancelled flag (i.e. isCancelled()
). SwingWorker
leaves how to handle the interrupt up to you.
For more information, see Cancelling Background Tasks.
Solution 3:
you can try overidding the done() method and put it in try catch and catch the java.util.concurrent.CancellationException. Something like
. . .
@Overide
done() {
try {
get();
} catch (CancellationException e) {
// Do your task after cancellation
}
}
. . .
Solution 4:
I think you have to restart the counter after every stop.
For startButton, you have to have worker restarted as in
private JButton startButton = new JButton(new AbstractAction("Start") {
@Override
public void actionPerformed(ActionEvent arg0) {
if(!isStarted) {
worker = new Worker(); // New line
worker.execute();
isStarted = false;
}
}
});
To stop you can use
worker.setStopFlag(); // in stopButton actionPerformed block.
in Worker class private boolean stopFlag = false;
and add
if( stopFlag)
break;
after Thread.sleep(60); and finally put setter for stopFlag at the end of Worker class as
void setStopFlag(){
stopFlag = true;
}
By the way, you can use cancel(true) if you want to have exception exit.