Search code examples
javamultithreadingjprogressbar

Update JProgressBar from new Thread


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.


Solution

  • 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.