If I flood the Swing Event Queue from Java with a separate thread using SwingUtilities.invokeLater(..)
, the Event Dispatch Thread can't keep up with the pace, the EventQueue fills up and the application behaves sluggish.
For example... in the following example I can see only a few of the integers showing up on the screen (mac os-x yosemite, java 8 update 25):
import javax.swing.*;
import java.awt.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.IntStream;
public class SwingForcePaintingQuestion {
public static void main(String[] args) throws InterruptedException {
final AtomicReference<JLabel> labelRef = new AtomicReference<>();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame("Frame42");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(600, 400));
frame.getContentPane().setLayout(new BorderLayout());
JLabel label = new JLabel("Hello");
label.setHorizontalAlignment(SwingConstants.CENTER);
frame.add(label, BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
labelRef.set(label);
}
});
while (labelRef.get() == null) {
Thread.sleep(1);
}
Thread.sleep(1000);
System.out.println("Starting filling the EventQueue");
int start = 1;
int endExclusive = 10000000;
IntStream.range(start, endExclusive).forEach(value ->
SwingUtilities.invokeLater(() -> {
labelRef.get().setText(value + "");
})
);
SwingUtilities.invokeLater(() -> labelRef.get().setText("Done. Did you see all values between " + start + " and " + endExclusive + "?"));
}
}
Is there any way to "slow things down", so that I can actually see every change in the GUI? Kind of calling some kind of repaint
method somewhere after calling setText(..)
on the label?
A wild flickering would be totally ok, since I expect my eye is "slower" than the pixels can change. At the moment the example behaves "strange" in a way that at the end I see a certain number like let's say 1070201 for a full second, then I see 1531452 for a full second.
Of course, I could use SwingUtilities.invokeAndWait(..)
instead of SwingUtilities.invokeLater(..)
and establish backpressure to the "producing" main thread, to prevent "filling up" the event queue. Isn't there an other way?