I have a class called WaitBox that I would like to pop up, show a progress bar, and then close when the progress bar reaches 100%. Right now, it pops up, but what's weird is that it waits until the code after it finished to draw the components (progress bar) in the WaitBox...
When I run the below code, the JDialog pops up, but it's just white, like how it looks before the components are drawn on it. It runs the coded below it (the nested for loops), and when that finished, it draws the components on the JDialog. Why is this happening, and how can I fix it?
WaitBox class:
public class WaitBox extends JDialog implements Runnable {
private static final long serialVersionUID = 1L;
private int width = 450;
private int height = 200;
public static int widthOfBar = 400;
private int heightOfBar = 50;
private JPanel container;
private JProgressBar progressBar;
private Thread thread;
private boolean running = false;
public WaitBox() {
initializeComponents();
add(container);
pack();
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
setTitle("Loading...");
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setResizable(false);
setLocationRelativeTo(null);
setVisible(true);
}
private void initializeComponents() {
container = new JPanel();
container.setPreferredSize(new Dimension(width, height));
progressBar = new JProgressBar(0, widthOfBar);
progressBar.setPreferredSize(new Dimension(widthOfBar, heightOfBar));
progressBar.setStringPainted(true);
progressBar.setValue(0);
container.add(progressBar);
}
public void run() {
while (running) {
System.out.println(Fill.currentPos);
progressBar.setValue((int) Fill.currentPos);
if (progressBar.getValue() >= widthOfBar) running = false;
}
stop();
}
public synchronized void start() {
running = true;
thread = new Thread(this);
thread.start();
}
public synchronized void stop() {
running = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
setCursor(null);
dispose();
}
}
How it's being called:
WaitBox waitBox = new WaitBox();
waitBox.start();
for (int yy = 0; yy < Constants.map_height; yy++) {
for (int xx = 0; xx < Constants.map_width; xx++) {
image.setRGB(xx * 32, yy * 32, 32, 32, pixels, 0, 32);
}
}
Your stop
method is waiting for thread
to end, which is blocking the Event Dispatching Thread.
See Concurrency in Swing for more details
Your run
method is violating the single thread rules of Swing, updating the UI from outside the Event Dispatching Thread, remember, Swing is single threaded, but is also not thread safe.
You should consider using a SwingWorker
instead, which has progress and PropertyChange
support. See Worker Threads and SwingWorker for more details
Which is demonstrated:
among other places