Update JProgressBar from new Thread

0 votes
asked Apr 28, 2010 by dacto

How can I update the JProgressBar.setValue(int) from another thread? My secondary goal is do it in the least amount of classes possible.

Here is the code I have right now:

// Part of the main class....
pp.addActionListener(
        new ActionListener(){
            public void actionPerformed(ActionEvent event){
                new Thread(new Task(sd.getValue())).start(); 
            }
        });

public class Task implements Runnable {
    int val;
    public Task(int value){
        this.val = value;
    }

    @Override
    public void run() {
        for (int i = 0; i <= value; i++){ // Progressively increment variable i 
            pbar.setValue(i); // Set value 
            pbar.repaint(); // Refresh graphics 
            try{Thread.sleep(50);} // Sleep 50 milliseconds 
            catch (InterruptedException err){} 
        } 
    }
}

pp is a JButton and starts the new thread when the JButton is clicked.

pbar is the JProgressBar object from the Main class.

How can I update its value?(progress)

The code above in run() cannot see the pbar.

3 Answers

0 votes
answered Apr 28, 2010 by cheok-yan-cheng
  • There is need not to call pbra.repaint explicitly.
  • Update JProgressBar shall be done through GUI dispatch thread.

SwingUtilities.invokeLater(new Runnable() {
    public void run() {
        // Remember to make pbar final variable.
        pbar.setValue(i);
    }
});
0 votes
answered Apr 28, 2010 by chris-dennett

You shouldn't do any Swing stuff outside of the event dispatch thread. To access this, you need to create a Runnable with your code in run, and then pass that off to SwingUtilities.invokeNow() or SwingUtilities.invokeLater(). The problem is that we need a delay in your JProgressBar checking to avoid jamming up the Swing thread. To do this, we'll need a Timer which will call invokeNow or later in its own Runnable. Have a look at http://www.javapractices.com/topic/TopicAction.do?Id=160 for more details.

0 votes
answered Apr 28, 2010 by ring-bearer

Always obey swing's rule

Once a Swing component has been realized, all code that might affect or depend on the state of that component should be executed in the event-dispatching thread.

What you can do is to create an observer that will update your progress bar -such as - in this instance you want to show progress of data being loaded on click of a button. DemoHelper class implements Observable and sends updates to all observers on when certain percent of data is loaded. Progress bar is updated via public void update(Observable o, Object arg) {

class PopulateAction implements ActionListener, Observer {

    JTable tableToRefresh;
    JProgressBar progressBar;
    JButton sourceButton;
    DemoHelper helper;
    public PopulateAction(JTable tableToRefresh, JProgressBar progressBarToUpdate) {
        this.tableToRefresh = tableToRefresh;
        this.progressBar = progressBarToUpdate;
    }

    public void actionPerformed(ActionEvent e) {
        helper = DemoHelper.getDemoHelper();
        helper.addObserver(this);
        sourceButton = ((JButton) e.getSource());
        sourceButton.setEnabled(false);
        helper.insertData();
    }

    public void update(Observable o, Object arg) {
        progressBar.setValue(helper.getPercentage());
    }
}

Shameless plug: this is from source from my demo project Feel free to browse for more details.

Welcome to Q&A, where you can ask questions and receive answers from other members of the community.
Website Online Counter

...