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
andJProgressBar
exampleSwingWorker
andJProgressBar
exampleSwingWorker
andJProgressBar
exampleSwingWorker
andJProgressBar
exampleSwingWorker
and dual weldingJProgressBar
exampleSwingWorker
andJProgressBar
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...
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
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) fromThread.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
orRunnable#Thread
withprogress.setValue(i);
wrapped intoinvokeLater
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:
(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();
}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
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
"Unable to Acquire Application Service" Error While Launching Eclipse
Migration from Struts 1 to Struts 2
Differencebetween I++ & ++I in a for Loop
Is a Java Array of Primitives Stored in Stack or Heap
Efficient Swapping of Elements of an Array in Java
Java:Non-Static Variable Cannot Be Referenced from a Static Context Error
Default Values and Initialization in Java
Java8: Why Is It Forbidden to Define a Default Method for a Method from Java.Lang.Object
Where to Find Source Code for Java.Lang Native Methods
Java Ioexception "Too Many Open Files"
Jtable Disable Checkbox in Cell
Bytebuffer.Allocate() VS. Bytebuffer.Allocatedirect()
How to Redirect to Login Page When Session Is Expired in Java Web Application
Is Jdk "Upward" or "Backward" Compatible
How to Simulate Keyboard Presses in Java