What I am trying to do ?
At the click of the Start JButton
, the SwingWorker
will execute. Inside the doInBackground(
comments
@kleopatra that's a documentation bug, fixed in jdk7 at least :-), please which of JDKs those bugs are shown as from carousel ....,
wait/notify is for thread, SwingWorker is Future, very bad implemented, means without notifiers, you put something to the tube and waiting on another side,
seems like as nothing betweens one and second side of this tube, this reason why I tried to invoke Thread, Runnable, Executor(Runnable) from doInBackground, and to ignore publish, process, setProcess
another funny issue is to get() and exception(s) all exception, not only 1st. from one and second side of this tube
there are two ways how to use SwingWokrer
try to avoid to use SwingWorker
use doInBackground as bridge for workers thread, for output to use publish, process, setProcess, wait for done(), and use done() as notifier for get an exception, notifier that SwingWorker ended
if I add Thread.sleep(...), it does work, though, it throws a InterruptedException
The code that apparently produces the exception (copied from OP's edit):
while (!isCancelled()) {
counter %= arrNames.length;
// System.out.format("Counter : %d%n", counter);
publish(arrNames[counter]);
try {
Thread.sleep(30); // throws
} catch (InterruptedException ie) {
ie.printStackTrace();
}
counter++;
}
The reason, though, is the code that cancels the worker (in the actionListener):
backgroundTask.cancel(true);
which explicitly tells the worker to cancel by .. interrupting the thread. From its api doc:
mayInterruptIfRunning - true if the thread executing this task should be interrupted; otherwise, in-progress tasks are allowed to complete
As an aside: catching the exception and doing nothing (thereby effectively ignoring the interrupt) is not the best of ideas. Probably not too damaging in this case - due to checking the cancelled status. Typical worker implementations either catch and return, after doing some internal cleanup if needed, or don't handle it at all.
Amplifying on the other answers, don't update the GUI from your background thread, which blocks the EDT, and don't try to avoid the problem with invokeLater()
. Instead, publish()
the desired result and update both statusLabel
and tArea
in process()
, as suggested below. For testing, Thread.sleep(100)
simulates a small latency, but you can use Thread.yield()
, as shown here. You can also update the GUI in a PropertyChangeListener
, as shown here.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.*;
import javax.swing.*;
public class SwingWorkerExample1 {
private JLabel statusLabel;
private JTextArea tArea;
private JButton startButton;
private JButton stopButton;
private BackgroundTask backgroundTask;
private ActionListener buttonActions = new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
JButton source = (JButton) ae.getSource();
if (source == startButton) {
startButton.setEnabled(false);
stopButton.setEnabled(true);
backgroundTask = new BackgroundTask();
backgroundTask.execute();
} else if (source == stopButton) {
backgroundTask.cancel(true);
stopButton.setEnabled(false);
startButton.setEnabled(true);
}
}
};
private void displayGUI() {
JFrame frame = new JFrame("Swing Worker Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel();
contentPane.setBorder(
BorderFactory.createEmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(5, 5));
statusLabel = new JLabel("Status Bar", JLabel.CENTER);
tArea = new JTextArea(20, 20);
tArea.setWrapStyleWord(true);
tArea.setLineWrap(true);
JScrollPane textScroller = new JScrollPane();
textScroller.setBorder(
BorderFactory.createTitledBorder("Textual OUTPUT : "));
textScroller.setViewportView(tArea);
startButton = new JButton("Start");
startButton.addActionListener(buttonActions);
stopButton = new JButton("Stop");
stopButton.setEnabled(false);
stopButton.addActionListener(buttonActions);
JPanel buttonPanel = new JPanel();
buttonPanel.add(startButton);
buttonPanel.add(stopButton);
contentPane.add(statusLabel, BorderLayout.PAGE_START);
contentPane.add(textScroller, BorderLayout.CENTER);
contentPane.add(buttonPanel, BorderLayout.PAGE_END);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private class BackgroundTask extends SwingWorker<Void, String> {
private int counter = 0;
private String[] arrNames = {"US Rates Strategy Cash",
"Pavan Wadhwa(1-212) 844-4597", "Srini Ramaswamy(1-212) 844-4983",
"Meera Chandan(1-212) 855-4555", "Kimberly Harano(1-212) 823-4996",
"Feng Deng(1-212) 855-2555", "US Rates Strategy Derivatives",
"Srini Ramaswamy(1-212) 811-4999",
"Alberto Iglesias(1-212) 898-5442",
"Praveen Korapaty(1-212) 812-3444", "Feng Deng(1-212) 812-2456",
"US Rates Strategy Derivatives", "Srini Ramaswamy(1-212) 822-4999",
"Alberto Iglesias(1-212) 822-5098",
"Praveen Korapaty(1-212) 812-3655", "Feng Deng(1-212) 899-2222"};
public BackgroundTask() {
statusLabel.setText((this.getState()).toString());
}
@Override
protected Void doInBackground() {
while (!isCancelled()) {
counter %= arrNames.length;
publish(arrNames[counter]);
counter++;
try {
Thread.sleep(100); // simulate latency
} catch (InterruptedException ex) {
publish("Cancelled: " + isCancelled());
}
}
return null;
}
@Override
protected void process(java.util.List<String> messages) {
statusLabel.setText((this.getState()).toString());
for (String message : messages) {
tArea.append(String.format(message + "%n"));
}
}
}
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
new SwingWorkerExample1().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}