1

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.

2 Answers2

1

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.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • I edited my code to a more minimal representation. The full code can take anywhere between a few minutes to over an hour to execute so, assuming I understand you, I don't think it's due to the code being executed too fast. – Branch of Light Aug 05 '16 at 17:43
0

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.

Anya Shenanigans
  • 91,618
  • 3
  • 107
  • 122
  • That's amazing! Thank you! So if I wait for the results on another thread how could I go about returning them to the parent function? I imagine .wait() will just block the EDT too. – Branch of Light Aug 05 '16 at 18:13
  • I found a solution for that thankfully. Just had to refactor some code. Thanks again! – Branch of Light Aug 05 '16 at 18:53