Why do people run Java GUI's on the Event Queue
Asked Answered
T

2

9

In Java, to create and show a new JFrame, I simply do this:

public static void main(String[] args) {
   new MyCustomFrameClass().setVisible(true);
}

However, I have seen many people doing it like this:

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            new MyCustomFrameClass().setVisible(true);
       }
    });
}

Why? Are there any advantages?

Tinker answered 10/6, 2010 at 20:19 Comment(0)
H
7

The rules governing what needs to be performed on the EDT (I see "EDT" more often used than "Event Queue") have changed during Java's lifetime. And everytime the "rules" changed, Sun advised doing more and more "GUI related" work on the EDT.

Why do people run Java GUI’s on the EDT?

  • Because the official guidelines advise doing so.

  • Because doing so will help dodge a lot of threading bugs related to the GUI.

Note, and this is not very well known, that the EDT actually does crash once in a while, because Swing itself has a few bugs. Every non-trivial Swing application is using Swing APIs that have, well, bugs and hence once in a while the EDT dies.

You never see it and it isn't a cause of concerns, because when the EDT dies it is automagically restarted.

Basically, do all GUI-related stuff on the EDT and do all lenghty operations outside the EDT (as to not block the EDT).

EDIT you asked for an example as to how to run a lenghty operation outside the EDT. There are several ways to do this. In the simplest case, you simply create and start a new Thread, from the EDT. Here's one example: the listener callback shall be called when the user clicks on a button, we know that this shall happen on the EDT...

    JButton jb = ...
    jb.addActionListener( new ActionListener() {
        public void actionPerformed( final ActionEvent e ) {
          final Thread t = new Thread( new Runnable() {
           public void run() {
             // this shall get executed, after start() has been called, outside the EDT    
             }
           });
           t.start();
        }
    } );

For more complicated examples, you want to read on SwingWorker, etc.

Hofmann answered 10/6, 2010 at 21:28 Comment(7)
How can I do operations outside the EDT if they need to be started from my GUI? (button event, etc) Also, do I need to use the EDT only for the main frame? If the user opens another JFrame from the main frame (for example an option window), do I need to start it on the EDT?Tinker
@asmo: you need the work on the EDT for everything related to the GUI (so in your "option window" example, yup, that needs to be done on the EDT too).Hofmann
It's unlikely that the EDT would crash. Unchecked exceptions thrown in EDT dispatch are caught, dumped and the thread goes on. There is a mechanism for the thread to exit and later for a new one to replace it, but that's so the process can exit without calling System.exit if no windows are realised and there are no other non-daemon threads.Transmitter
If I create and show the option window like this "new OptionFrame().setVisible(true);" from an actionPerformed method that's called from the main JFrame, do I need to wrap the "new OptionFrame().setVisible(true);" in the invokeLater() method to put it in the EDT or is it already in the EDT?Tinker
Teaching spawning Threads to do background work is too simple - it must be governed. Otherwise this program grows up, has lots of these, reaches production status, and has race conditions all over with unfixable bugs.Drug
@Tom Hawtin - tackline: I dispute that. This is not the behavior I see in IntelliJ IDEA, nor in my applications (non-trivial Swing app). I started a new question here, with a code example, which I need explanation about: stackoverflow.com/questions/3020757Hofmann
@Hofmann It does indeed seem that the behaviour has changed in the current Sun/Oracle implementation (to something complicated).Transmitter
C
3

This line is modifying a Swing component since your custom frame is a subclass of JFrame:

new MyCustomFrameClass().setVisible(true);

Generally, you should never modify a Swing component unless you are on the Event Dispatch Thread (EDT).

The following code will run whatever is in the Runnable on the EDT.

EventQueue.invokeLater(Runnable);

Now, the setVisible(true) call will be on the EDT as it should.

Clump answered 10/6, 2010 at 20:33 Comment(2)
I meant to create an instance of a JFrame subclass, not directly a JFrame. Sorry for the confusion. (I updated my original post)Tinker
The same still applies to any subclass of any swing component. It doesn't change anything. (@asmo)Clump

© 2022 - 2024 — McMap. All rights reserved.