I have two threads. One is running the business logic from my BulkProcessor class which updates the BulkProcessor.getPercentComplete() variable:
public void run(){
new SwingWorker<Void,Void>() {
protected Void doInBackground() throws Exception {
BulkProcessor.main(jTextField0.getText(), jTextField1.getText());
return null;
};
}.execute();
}
My other thread is what updates the jProgressBar's value in my BulkGUI class:
public void update(){
jProgressBar0.setStringPainted(true);
jProgressBar0.repaint();
new SwingWorker<Void,Integer>() {
protected Void doInBackground() throws Exception {
do
{
percentComplete = BulkProcessor.getPercentComplete();
publish(percentComplete);
Thread.sleep(100);
} while(percentComplete < 100);
return null;
}
@Override
protected
void process(List<Integer> progress)
{
jProgressBar0.setValue(progress.get(0));
}
}.execute();
}
I call the two threads when the Process button is clicked:
private void jButton0ActionActionPerformed(ActionEvent event) {
run();
update();
}
Running this the first time works exactly as expected. However selecting the Process button a second time has no affect on the jProgressBar. The local variable percentComplete in the update thread remains at 100, and does not update as it does the first run. I tested the percentComplete variable from the BulkProcessor class, and this variable does in fact update as expected. So for some reason the thread is not fetching the update values using BulkProcessor.getPercentComplete() the second time the thread is called. Anybody have any insight on this? Any help is much appreciated.
I'm guessing that your problem is likely because percentComplete is maximum the second time you press your button. Suggestions:
doInBackground(...)
method.run()
and then update()
as you're doing, getting two threads to run concurrently looks dangerous to me, a possible set up for a race condition.
Edit
You should look into using a SwingWorker's progress property with a PropertyChangeListener. For instance:
public class FooGUI {
// .....
public void myRun() {
String text1 = someTextField.getText();
String text2 = otherTextField.getText();
final BulkProcessor bulkProcessor = new BulkProcessor(text1, text2);
bulkProcessor.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent pcEvt) {
if (pcEvt.getPropertyName().equals("progress")) {
int progress = bulkProcessor.getProgress();
someProgressBar.setValue(progress);
}
}
});
}
}
class BulkProcessor extends SwingWorker<Void, Void> {
private Random random = new Random(); // just for SSCCE sake
private String text1;
private String text2;
public BulkProcessor(String text1, String text2) {
this.text1 = text1;
this.text2 = text2;
// not sure what you do with these texts....
}
@Override
protected Void doInBackground() throws Exception {
int progress = 0;
while (progress <= 100) {
progress = random.nextInt(5); // just as a for instance
// your code will do something else of course
setProgress(progress);
Thread.sleep(300);
}
return null;
}
}
For example:
import java.awt.event.*;
import java.beans.*;
import java.util.Random;
import javax.swing.*;
@SuppressWarnings("serial")
public class Foo3 extends JPanel {
private static final String DEFAULT_SPEED = "15";
private JTextField speedTextField = new JTextField(DEFAULT_SPEED, 5);
private JProgressBar someProgressBar = new JProgressBar();
private RunAction runAction = new RunAction();
private JButton runButton = new JButton(runAction);
public Foo3() {
speedTextField.setAction(runAction);
add(new JLabel("Speed:"));
add(speedTextField);
add(someProgressBar);
add(runButton);
}
public void myRun() {
String speedText = speedTextField.getText();
try {
int speed = Integer.parseInt(speedText);
final BulkProcessor bulkProcessor = new BulkProcessor(speed);
bulkProcessor.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent pcEvt) {
if (pcEvt.getPropertyName().equals("progress")) {
int progress = bulkProcessor.getProgress();
someProgressBar.setValue(progress);
}
if (pcEvt.getPropertyName().equals("state")) {
if (bulkProcessor.getState().equals(
SwingWorker.StateValue.DONE)) {
someProgressBar.setValue(0);
setGuiEnabled(true);
}
}
}
});
setGuiEnabled(false);
bulkProcessor.execute();
} catch (NumberFormatException e) {
String text = "Speed of " + speedTextField.getText()
+ " is invalid. Please enter an integer";
JOptionPane.showMessageDialog(this, text, "Invalid Speed Value",
JOptionPane.ERROR_MESSAGE);
speedTextField.setText(DEFAULT_SPEED);
}
}
private class RunAction extends AbstractAction {
public RunAction() {
super("Run");
putValue(MNEMONIC_KEY, KeyEvent.VK_R);
}
@Override
public void actionPerformed(ActionEvent arg0) {
myRun();
}
}
private void setGuiEnabled(boolean enabled) {
runButton.setEnabled(enabled);
speedTextField.setEnabled(enabled);
}
private static void createAndShowGui() {
Foo3 mainPanel = new Foo3();
JFrame frame = new JFrame("Foo3");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class BulkProcessor extends SwingWorker<Void, Void> {
private Random random = new Random(); // just for SSCCE sake
private int speed;
public BulkProcessor(int speed) {
this.speed = speed;
}
@Override
protected Void doInBackground() throws Exception {
int progress = 0;
while (progress <= 100) {
progress += random.nextInt(speed);
setProgress(progress);
Thread.sleep(300);
}
return null;
}
}