Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java update progressbar

Tags:

java

swing

I have a JFrame and following components.

JButton = jButton1 Progress Bar = progressBar and its public static JLabel = status and its public static

When button clicks then different statements execute. I want to update my progressbar after each statement. Here is my code

   private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
        Task pbu = new Task(25, "Step 1....");
        pbu.execute();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }

        pbu = new Task(50, "Step 2....");
        pbu.execute();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }

        pbu = new Task(75, "Step 3....");
        pbu.execute();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }

        pbu = new Task(100, "Done");
        pbu.execute();
    }

Here is my Task Class extended with SwingWorker

public class Task extends SwingWorker{

    private int progress;
    private String stat;

    public Task(int pr, String st) {
        progress = pr;
        stat = st;
    }

    @Override
    protected Object doInBackground() throws Exception {
        NewJFrame1.progressBar.setValue(progress);
        NewJFrame1.status.setValue(stat);
        return null;
    }

}

Any idea how can I solve this problem?

like image 824
user704006 Avatar asked Jun 06 '11 17:06

user704006


2 Answers

   @Override
    protected Object doInBackground() throws Exception {
        NewJFrame1.progressBar.setValue(progress);
        NewJFrame1.status.setValue(stat);
        return null;
    }

You don't want to update GUI components off of the Swing thread. SwingWorker provides hooks for doing stuff back on the Event Dispatch Thread, that's what it's designed for. Call the publish method from doInBackground and override process to detail with incremental updates. Or, if you only need to update the GUI when it's finished, override the done() method.

A very simple example:

//...in some concrete implementation of SwingWorker<Void, Integer>
protected Void doInBackground() throws Exception {
    //do 10% of task
    doLongOp();
    publish(10);

    //do another 20% of task
    doAnotherLongOp();
    publish(20);

    return null;
}

protected void process(List<Integer> pieces) {
    for (Integer percent : pieces ) {
       progressBar.setValue(progressBar.getValue() + percent);
    }
}

Edit

@mKorbel makes a good point that for the above to work it needs to extend SwingWorker<Void, Integer>...Void being the overall return value type (in this case indicating there's no return value) and Integer being the type of the incremental updates.

If the worker produces an actual final result (that will be retrieved with get()) then that type can be used in place of Void. I had left out these details since I didn't include the class declaration.

See

  • SwingWorker
like image 192
Mark Peters Avatar answered Nov 01 '22 10:11

Mark Peters


In addition to the answer from Mark, you really don't want to sleep in the actionPerformed() method. This method is (if linked to a GUI component) called by the AWT/Swing event dispatch thread, the same thread that also does painting and everything. As long as your method is not finished, your GUI will be blocked.

Do all your waiting in a SwingWorker or another thread.

like image 2
Paŭlo Ebermann Avatar answered Nov 01 '22 10:11

Paŭlo Ebermann