Jprogressbar Isn't Progressing

JProgressBar isn't progressing

Use a combination with SwingWorker.
See an example here:
SwingWorker and Progress Bar

@Hovercraft: You're right. Allow me to refer to the corresponding SwingWorker page of JavaDoc, in my opinion this explains the situation best.

JProgressBar not working properly

Swing is a single threaded environment, that is, there is a single thread which is responsible for processing all the events that occur within the system, including repaint events. Should anything block this thread for any reason, it will prevent Swing from processing any new events, including, repaint events...

So all this ...

EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(BandListGenerator.class.getName()).log(Level.SEVERE, null, ex); }
jProgressBar2.setValue(progress);
}
});

Is constantly pausing the Event Dispatching Thread, preventing it from actually doing any updates (or at least spacing them randomly)...

It's also likely that your outer loop is been run from within the context of the EDT, meaning that until it exists, nothing in the Event Queue will be processed. All your repaint requests will be consolidated down to a single paint request and voila, instant filled progress bar...

You really should use a SwingWorker - I know you said you tried one, but you've not shown any code as to your attempt in this regards, so it's difficult to know why it didn't work, however...

  • SwingWorker and JProgressBar example
  • SwingWorker and JProgressBar example
  • SwingWorker and JProgressBar example
  • SwingWorker and JProgressBar example
  • SwingWorker and dual welding JProgressBar example
  • SwingWorker and JProgressBar example

And forgive me if we haven't said this a few times before :P

Java - Progress Bar Not Progressing

The calculation has to be done in an extra thread. This is because the currently running thread is blocking the repaint of the UI until the calculation is done.

JProgressBar not updating

Your showProgress method is being executed within the context of the Event Dispatching Thread. The EDT is responsible for, amongst other things, processing paint requests. This means that so long as your for-loop is executing, the EDT can not process any new paint requests (or handle the invokeLater events either) as it is blocking the EDT.

While there are any number of possible ways to solve the problem, based on your code example, the simplest would be to use a SwingWorker.

It has the capacity to allow your to execute the long running task the a background thread (freeing up the EDT), but also allows you means for publishing updates (if required) so that they can be processed in the EDT and also provides handy progress notification.

For example...

Sample Image

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;

public class SwingWorkerProgress {

public static void main(String[] args) {
new SwingWorkerProgress();
}

public SwingWorkerProgress() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}

JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

public class TestPane extends JPanel {

private JProgressBar pbProgress;
private JButton start;

public TestPane() {

setBorder(new EmptyBorder(10, 10, 10, 10));
pbProgress = new JProgressBar();
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(4, 4, 4, 4);
gbc.gridx = 0;
gbc.gridy = 0;
add(pbProgress, gbc);

start = new JButton("Start");
gbc.gridy++;
add(start, gbc);

start.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
start.setEnabled(false);
ProgressWorker pw = new ProgressWorker();
pw.addPropertyChangeListener(new PropertyChangeListener() {

@Override
public void propertyChange(PropertyChangeEvent evt) {
String name = evt.getPropertyName();
if (name.equals("progress")) {
int progress = (int) evt.getNewValue();
pbProgress.setValue(progress);
repaint();
} else if (name.equals("state")) {
SwingWorker.StateValue state = (SwingWorker.StateValue) evt.getNewValue();
switch (state) {
case DONE:
start.setEnabled(true);
break;
}
}
}

});
pw.execute();
}
});

}
}

public class ProgressWorker extends SwingWorker<Object, Object> {

@Override
protected Object doInBackground() throws Exception {

for (int i = 0; i < 100; i++) {
setProgress(i);
try {
Thread.sleep(25);
} catch (Exception e) {
e.printStackTrace();
}
}

return null;
}
}
}

Check out Concurrency in Swing for more details

Java GUI - Progress bar doesn't update until the async task is finished

Stop and take a closer look at Worker Threads and SwingWorker.

A SwingWorker is meant to allow you to perform a long running task, which may produce intermediate results, and allow you to publish those results back to the Event Dispatching Thread to be safely processed (via the process method).

You "could" publish the progress updates and update the progress bar in process method, but SwingWorker already provides a progress property, which you can monitor. Take a look at the SwingWorker JavaDocs for a number of ready made examples!

Run Example

Simple Example

import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;

public class Test {

public static void main(String[] args) {
new Test();
}

public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}

ProgressPane progressPane = new ProgressPane();
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(progressPane);
frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);

// progressPane.doWork();
}
});
}

public class ProgressPane extends JPanel {

private JProgressBar progressBar;
private JButton startButton;

public ProgressPane() {

setLayout(new GridBagLayout());
progressBar = new JProgressBar();

GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
add(progressBar, gbc);
startButton = new JButton("Start");
gbc.gridy = 1;
add(startButton, gbc);

startButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
startButton.setEnabled(false);
doWork();
}
});

}

public void doWork() {

Worker worker = new Worker();
worker.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())) {
progressBar.setValue((Integer) evt.getNewValue());
}
}
});

worker.execute();

}

public class Worker extends SwingWorker<Object, Object> {

@Override
protected void done() {
startButton.setEnabled(true);
}

@Override
protected Object doInBackground() throws Exception {

for (int index = 0; index < 1000; index++) {
int progress = Math.round(((float) index / 1000f) * 100f);
setProgress(progress);

Thread.sleep(10);
}

return null;
}
}
}
}

JProgressBar does not update within the loop

  • Swing is single threaded,

  • all updates must be done on EDT,

  • all events in current EDT are painted in GUI in one moment,

  • Thread.sleep to lock execution of event in EDT, repaint can be painted at the end of for_loop, after all lock(s) from Thread.sleep are executed, more in Oracle trail - Concurency in Swing and EventDispatchThread


output from AWT (Swing) Listener - ActionListener, should be done if all events inside actionPerformed are executed, then there is executed only progress.setValue(progress.getMinimum());, doesn't matter if is there Thread.sleep or not

public void actionPerformed(ActionEvent e) -> progress.setValue(progress.getMinimum());

  • use SwingWorker or Runnable#Thread with progress.setValue(i); wrapped into invokeLater

  • for better help sooner post an SSCCE/MCVE, short, runnable, compilable

ProgressBar doesn't change its value in Java

The value of the progress bar is really updated. But it isn't simply on the screen yet. Often, we use progress bars in loops. But, while you are in the loop, which you probably invoked by clicking a button it isn't painted. Why? Because you invoked it by clicking a button. When you click a button, all the code you've made for that button is being executed by the AWTEventThread. This is the same thread that keep track of all the Swing components, and checks wether they have to be repainted. That is the thread that makes your JFrame come alive. When you hover a button and the color changes a bit, it's done by the AWTEventThread.

So, while you are working in the loop, the AWTEventThread can't update the screen anymore.

This means there are two solutions:

  1. (Recommend) You should create a separate thread which executes the loop. This means the AWTEventThread can update the screen if necessary (when you call bar.setValue(...);)

    public void yourButtonClickMethod()
    {
    Runnable runner = new Runnable()
    {
    public void run() {
    //Your original code with the loop here.
    }
    };
    Thread t = new Thread(runner, "Code Executer");
    t.start();
    }
  2. Manually repaint the progress bar. I did it always with bar.repaint(); but I'm wondering if it will work. I though it was that method. If that doesn't work, try: bar.update(bar.getGraphics());.

JProgressBar too fast

The problem is, you're trying to update the progress within the context of the Event Dispatching Thread.

This basically means that while you are in you loop, the EDT is unable to process any paint request you are making.

What you need to do is some how offload the work to a separate thread and update the progress bar as needed. The problem with this, is you should never update the UI from any thread other then the EDT.

But don't despair, you have a number of options, the best is using a Swing Worker

Updated with example

Sample Image

public class SwingWorkerProgress {

public static void main(String[] args) {
new SwingWorkerProgress();
}

public SwingWorkerProgress() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}

JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

public class TestPane extends JPanel {

private JProgressBar pbProgress;
private JButton start;

public TestPane() {

setBorder(new EmptyBorder(10, 10, 10, 10));
pbProgress = new JProgressBar();
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(4, 4, 4, 4);
gbc.gridx = 0;
gbc.gridy = 0;
add(pbProgress, gbc);

start = new JButton("Start");
gbc.gridy++;
add(start, gbc);

start.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
start.setEnabled(false);
ProgressWorker pw = new ProgressWorker();
pw.addPropertyChangeListener(new PropertyChangeListener() {

@Override
public void propertyChange(PropertyChangeEvent evt) {
String name = evt.getPropertyName();
if (name.equals("progress")) {
int progress = (int) evt.getNewValue();
pbProgress.setValue(progress);
repaint();
} else if (name.equals("state")) {
SwingWorker.StateValue state = (SwingWorker.StateValue) evt.getNewValue();
switch (state) {
case DONE:
start.setEnabled(true);
break;
}
}
}

});
pw.execute();
}
});

}
}

public class ProgressWorker extends SwingWorker<Object, Object> {

@Override
protected Object doInBackground() throws Exception {
int i = 0;
int max = 2000;

while (i < max) {
i += 10;
int progress = Math.round(((float)i / (float)max) * 100f);
setProgress(progress);
try {
Thread.sleep(25);
} catch (Exception e) {
e.printStackTrace();
}
}

return null;
}
}
}


Related Topics



Leave a reply



Submit