Branch of Light Branch of Light - 4 months ago 34
Java Question

JProgress Bar Not Updating Within SwingWorker

I apologize for adding to the many JProgressBar update questions, but this has really been driving me crazy.

I have a JProgressBar being updated via a SwingWorker yet I'm still having the typical problem of the bar being updated after completion.

Here is the relevant code:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.swing.*;

public class SwingTest {

public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
init();
}
});
}

public static void init() {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
JProgressBar bar = new JProgressBar();

JButton button = new JButton("Start");
button.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
bar.setMaximum(100);
bar.setValue(0);

SwingWorker worker = new SwingWorker<String, Void>()
{
@Override
public String doInBackground()
{
int val = 0;
// +1 to make inclusive
for (int i = 0; i < 100; i++)
{
try
{
Thread.sleep(50);
} catch (InterruptedException e)
{
e.printStackTrace();
}

setProgress(++val);
}

return "Hello SwingWorker World";
}

@Override
public void done()
{
}
};

worker.addPropertyChangeListener(
new PropertyChangeListener()
{
public void propertyChange(PropertyChangeEvent evt)
{
if ("progress".equals(evt.getPropertyName()))
{
bar.setValue((Integer)evt.getNewValue());
}
}
}
);

worker.execute();

try
{
System.out.println("Return: " + worker.get().toString());
} catch (InterruptedException e1)
{
e1.printStackTrace();
System.out.println("Failed.");
} catch (ExecutionException e1)
{
e1.printStackTrace();
System.out.println("Failed.");
}
}
});

panel.add(button);
panel.add(bar);

frame.add(panel);
frame.pack();
frame.setSize(200,90);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}


If the problem is likely due to another section I will edit my question with more code if needed.

Thanks in advance.

EDIT: Stripped down code to a minimal product.

Answer

the problem in the code you've posted is when you start the SwingWorker, you then immediately wait for it to run. This blocks the event thread, which prevents the display from being updated:

worker.execute(); // This starts the thread in the background

try
{
     // This immediately stops the event handler waiting for the worker to finish
    System.out.println("Return: " + worker.get().toString());
} catch (InterruptedException e1)
{
    e1.printStackTrace();
    System.out.println("Failed.");
} catch (ExecutionException e1)
{
    e1.printStackTrace();
    System.out.println("Failed.");
}

If you comment out the entirety of that try-catch block, it will run and update the display.

If you need to wait for the result of the worker, then you should wait for the results on another thread, and allow the UI thread to continue.