0

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?

Peti
  • 1,670
  • 1
  • 20
  • 25
  • Using `invokeAndWait()` seems perfectly fine for your use case, why don't you want to use it? – Zhedar May 28 '15 at 13:56
  • 1
    What do you try to achive? Seems here you need to use Swing `Timer`. – alex2410 May 28 '15 at 14:00
  • I know `invokeAndWait(..)` works fine, I'm asking the question to get a better understanding what happens if the event queue fills up. – Peti May 28 '15 at 14:03
  • 1
    The [RepaintManager](http://docs.oracle.com/javase/8/docs/api/javax/swing/RepaintManager.html) collapses repaint requests. Also, Swing components are double buffered. If you want to see every number, try adding `labelRef.get().paintImmediately(0, 0, labelRef.get().getWidth(), labelRef.get().getHeight());` to the end of the invokeLater Runnable inside your forEach. – VGR May 28 '15 at 14:31
  • @VGR thanks a lot. I understand now much better what's going on "inside". I was looking for something like the `paintImmediately` method, which works fine. With this, I can see now the numbers changing and it "stucks" only when the garbage collector kicks in. – Peti May 28 '15 at 15:11

0 Answers0