My JProgressBar is not Updating Until it is 100%

15,399

Solution 1

You thread executes SwingUtilities.invokeLater. You're effectively running on Swing's Event Dispatch Thread. Not sure what are you trying to achieve. But it looks like you are blocking EDT and your while loop is not updated as MySetValue is not executed.

Consider using SwingWorker for lengthy operations. How to Use Progress Bars demonstrates use of SwingWorker with JProgressBar.

Make sure you call setValue method from the Event Dispatch Thread. You can use SwingUtilities.invokeLater for that. Read more about Threads and Swing.

Consider this simplified sample:

public static void main(String[] arguments) {
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(EXIT_ON_CLOSE);

    final JProgressBar bar = new JProgressBar(0, 100);

    Thread t = new Thread(){
        public void run(){
            for(int i = 0 ; i < 100 ; i++){
                final int percent = i;
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        bar.setValue(percent);
                    }
                  });

                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {}
            }
        }
    };
    frame.add(bar);
    frame.pack();
    frame.setVisible(true);
    t.start();
}

Solution 2

The problem is that you use a loop in the EDT that updates the progress. Until that loop exits, the EDT cannot dispatch events (like repaint, revalidate, invokeLater, mouse events, key events, etc...) preventing it from refreshing the progress bar.

You should try to find a way to let the EDT dispatch its events between each update of the progress bar. Ideally, you move your "work" outside the EDT with a SwingWorker, and meanwhile the progressbar get updated through property change listeners in the EDT.

For your information, in Java, methods and variables starts with a lower case letter. Your code is really hard to read for others.

Solution 3

Dynamic progress update of the progress bar is achieved via the below code:

 int progress = Math.round(((float)finished/(float)(total)) * 100);
 uploadPrgressBar.setIndeterminate(progress == 0);
 uploadPrgressBar.setValue(progress);
 uploadPrgressBar.update(uploadPrgressBar.getGraphics());

Call the method containing the above code in the loop(code logic) and it will dynamically update progress bar after each iteration

Solution 4

So, I tried to follow the tutorial and here is where I am at.

Ok, I have tried following tutorials but I keep getting lost somewhere. What I need is a class that creates and displays a progress bar (JProgressBar) that I can set the value of as I iterate over data loaded from a file and place into the database memory. My problems come that every example I have found has some kind of counter that fills the progress bar and executes from a "main" function. Every time I alter that tutorial to be a class that I can call at will and display the bar, I do not get the bar showing (ie the frame comes up but the bar does not even look like it is added to the frame until after the iteration is done). I have tried using SwingUtilities.invokeLater and SwingWorker (lastest attempt at class below) all having the same issue. To make matters worse, I can do a dbug.myMessage (basically sends to System.out) and see a message that shows that the bar is changing in memory just not showing. I am obviously missing something probably simple but I can't think of what it is.

Oh, one other thing, if I leave the tutorial as is (http://docs.oracle.com/javase/tutorial/displayCode.html?code=http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ProgressBarDemo2Project/src/components/ProgressBarDemo2.java) and just change the main to a createAndShow method, it works but of course it does not do what I need it to do.

I did post another question about this but have altered the class so much I thought it best to post a new question.

So, here is my altered code that does not seem to work:

public class MyProgressBar extends JPanel implements PropertyChangeListener, 
                                                     MyData, 
                                                     Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = -1632492668549544408L;

    private MyDebug         dbug               = new MyDebug( MyData.MYDEBUGCHECK.MYPROGRESSBAR.getOn() );

    public static final int MAX                = 100;
    public static final int WIDTH              = 400;
    public static final int HEIGHT             = 75;

    private JProgressBar    myBar              = new JProgressBar( SwingConstants.HORIZONTAL, 0, MAX );
    private JFrame          myFrame            = new JFrame();

    public  Task            task;


    class Task extends SwingWorker<Void, Void> {

        public int myValue = 0;

        @Override
        public Void doInBackground() {
            //Initialize progress property.
            setProgress(0);
            while (myValue < 100) {
                //Make random progress.
                //myValue += random.nextInt(10);
                setProgress( Math.min( myValue, 100 ) );
                dbug.myMessage( "MYPROGRESSBAR", "doInBackground", "Value is %3.2f %d", myBar.getPercentComplete(), myValue );
                myBar.repaint();
            }
            return null;
        }

        public void done() {
        }

        public void mySetValue( int percent ) {
            myValue = (int)( MAX * ( (double)percent / 100.0 ) );
            dbug.myMessage( "MYPROGRESSBAR", "mySetValue", "Value is %3.2f %d percent was %d", myBar.getPercentComplete(), myValue, percent );
        }

    }



    public MyProgressBar() {
        add(myBar);

        int x = ( MyData.SCREEN.width  / 2 ) - ( WIDTH  / 2);
        int y = ( MyData.SCREEN.height / 2 ) - ( HEIGHT / 2);

        this.setBounds( x, y, WIDTH, HEIGHT );

        myFrame.setBounds( x, y, WIDTH, HEIGHT );
        myFrame.setUndecorated(true);
        myFrame.getContentPane().setSize( new Dimension( WIDTH, HEIGHT ) );
        myFrame.setMinimumSize( new Dimension( WIDTH, HEIGHT ) );
        myFrame.setPreferredSize( new Dimension( WIDTH, HEIGHT ) );
        myFrame.setSize( new Dimension( WIDTH, HEIGHT ) );
        myFrame.setVisible(false);
        myFrame.getContentPane().setLayout(null);
        myFrame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);

        myBar.setStringPainted( true );
        myBar.setBorderPainted( true );
        myBar.setValue( 0 );
        myBar.setBounds( 0, 0, WIDTH, HEIGHT );
        myBar.addPropertyChangeListener( this );

        myFrame.add( myBar );

        //Create and set up the content pane.
        //JComponent newContentPane = new MyProgressBar();
        JComponent newContentPane = myBar;
        newContentPane.setOpaque(true);                     //content panes must be opaque

        myFrame.setContentPane(newContentPane);
        myFrame.pack();

    }

    public void createAndShow () {

        //Display the window.
        myFrame.setVisible(true);
        myFrame.repaint();

    }

    public void hideAndClear () {
        //myFrame.setVisible(false);
    }


    @Override
    public void propertyChange(PropertyChangeEvent args) {
        dbug.myMessage( "MYPROGRESSBAR", "propertyChange", "Value is %s", args.getPropertyName() );
        if ( "progress" == args.getPropertyName() ) {
            int progress = (Integer) args.getNewValue();
            //myBar.setValue(progress);
        }
    }

    public void start () {
        //Instances of javax.swing.SwingWorker are not reusuable, so
        //we create new instances as needed.
        task = new Task();
        task.addPropertyChangeListener(this);
        task.execute();
    }

}

Solution 5

The below snippet updates the progress bar while in progress

    SwingUtilities.invokeLater(new Runnable() {
           public void run() {
           progressBar.setValue((int)percentage);
           //below code to update progress bar while running on thread
           progressBar.update(progressBar.getGraphics());}
         });   
Share:
15,399
Patrick Aquilone
Author by

Patrick Aquilone

Updated on June 28, 2022

Comments

  • Patrick Aquilone
    Patrick Aquilone almost 2 years

    Ok, I have the following code.

    public class MyProgressBar extends JPanel implements MyData, Serializable {
    
        /**
         * 
         */
    
        public static final int MAX                = 10000;
        public static final int WIDTH              = 400;
        public static final int HEIGHT             = 75;
    
        private JProgressBar    MyBar              = new JProgressBar( SwingConstants.HORIZONTAL, 0, MAX );
        private JFrame          MyFrame            = new JFrame();
    
        private int             MyValue            = 0;
    
        private Thread          MyThread           = new Thread( new ProgressThread() );
    
    
    
        public MyProgressBar() {
            add(MyBar);
    
            int x = ( MyData.SCREEN.width  / 2 ) - ( WIDTH  / 2);
            int y = ( MyData.SCREEN.height / 2 ) - ( HEIGHT / 2);
    
            this.setBounds( x, y, WIDTH, HEIGHT );
    
            MyFrame.setBounds( x, y, WIDTH, HEIGHT );
            MyFrame.setUndecorated(true);
            MyFrame.getContentPane().setSize( new Dimension( WIDTH, HEIGHT ) );
            MyFrame.setMinimumSize( new Dimension( WIDTH, HEIGHT ) );
            MyFrame.setPreferredSize( new Dimension( WIDTH, HEIGHT ) );
            MyFrame.setSize( new Dimension( WIDTH, HEIGHT ) );
            MyFrame.setVisible(false);
            MyFrame.getContentPane().setLayout(null);
    
            MyBar.setStringPainted( true );
            MyBar.setBorderPainted( true );
            MyBar.setValue( 0 );
            MyBar.setBounds( 0, 0, WIDTH, HEIGHT );
    
            MyFrame.add( MyBar );
            MyFrame.pack();
            MyFrame.repaint();
    
        }
    
        public void MyUpdateBar() {
            MyBar.setValue( MyValue );
            MyBar.repaint();
            MyFrame.repaint();
            this.repaint();
            //dbug.Message( "MYPROGRESSBAR", "MyUpdateBar", "Value is %3.2f %d", MyBar.getPercentComplete(), MyValue );
        }
    
        public void MySetValue( int percent ) {
            MyValue = (int)( MAX * ( (double)percent / 100.0 ) );
            MyUpdateBar();
            //dbug.Message( "MYPROGRESSBAR", "MySetValue", "Value is %3.2f %d percent was %d", MyBar.getPercentComplete(), MyValue, percent );
        }
    
        public void CreateAndShow () {
            MyFrame.setVisible(true);
            MyThread.start();
        }
    
        public void HideAndClear () {
            MyThread.stop();
            //frame.setVisible(false);
        }
    
        class ProgressThread implements Runnable {
            public void run() {
                EventQueue.invokeLater(new Runnable() {
                    public void run() {
                        while( MyValue < MyBar.getMaximum() ) {
                            MyBar.setValue( MyValue );
                            MyBar.repaint();
                            MyFrame.repaint();
                            dbug.Message( "MYPROGRESSBAR", "THREAD", "Value is %3.2f %d", MyBar.getPercentComplete(), MyValue );
                        }
                    }
                });
            }
    
        }
    
    
    
    }
    

    As you can see, I have created a class that I want to have show the progress. What happens is I instantiate the class. Load my XML file, then as I am parsing data, I am calling to update the MyValue which I see when I let my dbug messages come out. However, the bar itself does not even show until it is 100% complete. I have read about threading and following someone else's example and if I left it as his example it worked. If I made a few tweaks (changing a loop in the thread to populate the setvalue of the progress bar to read a value) it does not even show until it is 100.

    What did I do wrong?

    Thanks!

  • Patrick Aquilone
    Patrick Aquilone almost 12 years
    I changed the EventQueue to be SwingUtilities and it behaves the same.
  • Patrick Aquilone
    Patrick Aquilone almost 12 years
    I didn't know that about the variables and methods. I will change my code to make it more readable. Thanks.
  • Guillaume Polet
    Guillaume Polet almost 12 years
    @JesterHawk that's what I figured, so I thought to at least let you know ;-)
  • tenorsax
    tenorsax almost 12 years
    @JesterHawk SwingUtilities.invokeLater is actually calling EventQueue.invokeLater. The issue is you're are blocking EDT in your while loop.
  • Patrick Aquilone
    Patrick Aquilone almost 12 years
    The problem that I have is I can get something like that to work. But I need to be able to call a method and set the percent complete from another class (the class the declared this) and when I try to add that in, I get nothing.