Branch of Light
Branch of Light

Reputation: 13

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.

Upvotes: 1

Views: 55

Answers (2)

Anya Shenanigans
Anya Shenanigans

Reputation: 94829

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.

Upvotes: 0

camickr
camickr

Reputation: 324167

Well, I don't know exactly what your code is doing but I don't see anywhere in your code where you have a "delay".

As a result the loop keeps executing and all the paint requests get consolidated into a single request so you only see the final value.

You can verify is this is the problem by simply adding a Thread.sleep() after the setProgress(...) method.

If this is the case the question is why are you using a progress bar since the code executes so fast.

Read the section from the Swing tutorial on How to Use Progress Bars and start with the working demo. You can then modify the working code to see what happens as you make your changes.

Upvotes: 1

Related Questions