You're at risk of blocking the Event Dispatching Thread (Thread.sleep
) or you are violating the single thread rules of Swing by updating the UI outside of the Event Dispatching Thread
Take a look at Concurrency in Swing for more details

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
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 | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JProgressBar pb = new JProgressBar();
pb.setStringPainted(true);
SwingWorker worker = new SwingWorker() {
@Override
protected Object doInBackground() throws Exception {
for (int index = 0; index < 1000; index++) {
int progress = Math.round((index / 1000f) * 100f);
setProgress(progress);
Thread.sleep(50);
}
return null;
}
};
worker.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
SwingWorker worker = (SwingWorker) evt.getSource();
if ("progress".equals(evt.getPropertyName())) {
pb.setValue(worker.getProgress());
}
}
});
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
frame.add(pb);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
worker.execute();
}
});
}
}
Updated
So, after digging about the WindowProgressBarUI
, it would seem that, that's the way it's designed to work...that is, it paints in chunks/blocks.
You can use setStringPainted
as I did in the example, which uses a different painting branch, but this might not suit your requirements
You can have a read through JProgressBar: low values will not be displayed for more details, but essentially, this is how the UI delegate is designed, so as to meet the requirements of the OS look and feel requirements