46

I am very curious why we have to use java.awt.EventQueue.invokeLater to control swing components.

Why can't we do that in a normal thread? What exactly is going on behind the scenes? From what I have noticed if I have a JFrame I can set visibility to true or false from the main thread without getting any errors, and it does seem to work. So what exactly do I achieve by using java.awt.EventQueue.invokeLater? I am also fully aware that I can use SwingUtilities.invokeLater but as explained here, they seem to be one and the same thing.

Thanks to anyone for their explanation. Hopefully this is a valid question.

EDIT: to answer wumpz question We can create a jframe

JFrame frame = new JFrame("Hello world");
frame.setSize(new Dimension(300, 300));
frame.setPreferredSize(new Dimension(300, 300));
frame.setMaximumSize(new Dimension(300, 300));
frame.setMinimumSize(new Dimension(300, 300));
frame.setVisible(true);
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

And on the same thread it was created do the following.

for (int i = 0; i < 34; i++)
{
    System.out.println("Main thread setting to "+(!frame.isVisible()));
    frame.setVisible(!frame.isVisible());
}

And no complaints.

dainichi
  • 2,231
  • 1
  • 13
  • 12
Quillion
  • 6,346
  • 11
  • 60
  • 97
  • Why are you now allowed to do that in a normal thread? Any Exceptions? – wumpz Mar 20 '14 at 13:38
  • It works because you're lucky - and because thread races are notoriously difficult to reproduce. The program may appear to work correctly, but it does not mean it's not buggy. Creating and modifying the components outside the EDT breaks the threading rules, but the breakage is not necessarily visible. The larger the program grows, the more likely it starts behaving badly sometimes, on some systems, and on some java versions. – kiheru Mar 20 '14 at 13:54
  • @wumpz, Read the section from the Swing tutorial on [Concurrency](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html) for a more complete explanation. – camickr Mar 20 '14 at 14:53

2 Answers2

55

The complete Swing processing is done in a thread called EDT (Event Dispatching Thread). Therefore you would block the GUI if you would compute some long lasting calculations within this thread.

The way to go here is to process your calculation within a different thread, so your GUI stays responsive. At the end you want to update your GUI, which have to be done within the EDT. Now EventQueue.invokeLater comes into play. It posts an event (your Runnable) at the end of Swings event list and is processed after all previous GUI events are processed.

Also the usage of EventQueue.invokeAndWait is possible here. The difference is, that your calculation thread blocks until your GUI is updated. So it is obvious that this must not be used from the EDT.

Be careful not to update your Swing GUI from a different thread. In most cases this produces some strange updating/refreshing issues.

Still there is Java code out there that starts a JFrame simple from the main thread. This could cause issues, but is not prevented from Swing. Most modern IDEs now create something like this to start the GUI:

public static void main(String args[]) {
    java.awt.EventQueue.invokeLater(new Runnable() {
        public void run() {
            new NewJFrame().setVisible(true);
        }
    });
}
smwikipedia
  • 61,609
  • 92
  • 309
  • 482
wumpz
  • 8,257
  • 3
  • 30
  • 25
  • +1 but - The difference is, that ... and must be called out of EDT by test isEventDis...., otherwise generating a few exceptions, valid for InitialThread too, because part of methods nested from AWT created EventQueue – mKorbel Mar 20 '14 at 13:59
  • Tested invokeLater in java 7. There are no exceptions thrown. – wumpz Mar 20 '14 at 14:06
  • 1
    about `Also the usage of EventQueue.invokeAndWait is possible here. The difference is ....` fast hands – mKorbel Mar 20 '14 at 14:11
  • 1
    Just add some of my understanding. In the last code snippet, the `main` thread can be viewed as kind of a `worker thread`. Only that it posts a message to the global `EventQueue` to inform the EDT to start the GUI rather than updates the GUI like worker thread usually does. And after that, the `main` thread exits. But the GUI will keep the process alive. – smwikipedia Jun 16 '16 at 02:20
  • So EventQueue.invokeLater in AWT is like handler.post in android. – Chaitanya Vaishampayan Sep 25 '18 at 02:49
  • Thank you very much, so the problem is I should do my work (especially the long ones) on a new thread to not freeze the GUI, but the second problem is that swing is not thread safe (it could break if multiple threads are updating the GUI), so `invokeLater` is the solution, it makes me able to create many threads all of them updating the GUI without breaking it. Did I get it right ? – Accountant م Dec 19 '19 at 11:32
12

All supported platforms offer single-threaded graphics libraries. Swing is cross-platform. Therefore, Swing GUI objects should be constructed and manipulated only on the event dispatch thread.

As an aside, SwingUtilities.invokeLater() is a cover for EventQueue.invokeLater() since version 1.3.

trashgod
  • 203,806
  • 29
  • 246
  • 1,045