Using SwingUtilities.invokeLater() in main method
Asked Answered
A

1

2

I recently saw a MVC java application in which the main method was written as:

    public static void main(String[] args) 
    {
        SwingUtilities.invokeLater(new Runnable() 
        {
            public void run() 
            {
                View view = new View();
                Model model = new Model();
                Controller controller = new Controller(view, model);
                controller.start();
            }
        });
    }

Wouldn't this make all the program (including both the model and the controller, that have nothing to do with Swing at all) run until the code ends in the AWT Event Dispatch Thread instead of the Main thread?

If this last was true, then that would be really bad for the app as it would block the EDT from carrying out the tasks it needs to (dispatching events, for example, as the model could be calculating other tasks). Is it correct?


There is a similar old post (not a duplicate from this one) that can suggest the code mentioned above is good practice, so it confused me even more.

Aleda answered 11/3, 2021 at 15:10 Comment(6)
Yes the model and controller effect Swing. You can't paint a Swing component if you don't have access to the data in the model. The controller notifies the view when the model has changed so the component can be repainted. So yes, the majority of the code will always execute on the EDT since all listener code executes on the EDT. The only code that doesn't execute on the EDT is when you create a Thread for long running background tasks. In those threads if you ever need to update the GUI you then need to use invokeLater(...) as well, or use a SwingWorker instead of a Thread.Vault
There is no UI before this run() method starts (and therefore no events to process, no repainting to be done). It stands to reason that what controller.start() does is make the whole UI visible and before that there is just nothing else to be done on the EDT.Horologist
So wouldn't it be much better to have the model, view and controller running on the main thread and use invokeLater(...) only in the view methods that really need to create/update the Swing UI? I don't see why should they all run in the EDT instead of the main thread.Aleda
The purpose of the code fragment that you show is to create the Swing UI and the model and to connect them together. There is no Swing update (in terms of reacting to user input) since there cannot be any user input before the run() methods ends. While you could split these tasks between main thread and EDT (and possibly gain a few milliseconds until the UI is first shown) it would also complicate the design of the application (multithreading is no easy topic) and litter the code base with invokeLater() calls. I would not do it until someone proves it to be necessary.Horologist
@ThomasKläger I see what you're saying, and yes the easiest and cleanest way by far would be to do it with a single invokeLater() on the main. But what if when creating the model it needs to read some files and instead of delaying a few milliseconds it delays a whole second? The point is that every code is different, and I believe only code creating or updating Swing should go to the EDT. With the approach you suggest, the EDT becomes the main thread.Aleda
You are confused between invokeLater() and invokeAndWait() the former is asynchronous and there is no BLOCKING but the later will wait for completion in the awt thread. Choice is yoursNorven
I
1

The purpose of the code fragment that you show is to create the Swing UI and the model and to connect them together.

There is no Swing update (in terms of reacting to user input) since there cannot be any user input before the run() methods ends.

While you could split these tasks between main thread and EDT (and possibly gain a few milliseconds until the UI is first shown) it would also complicate the design of the application (multithreading is no easy topic) and litter the code base with invokeLater() calls. I would not do it until someone proves it to be necessary.


IMHO the EDT is the main thread in any GUI application. Every reaction to user input starts in this thread and every update of the UI must be done in this thread.

Long running tasks should be done in a background thread - which usually means anything that takes more than a few milliseconds.

What if creating the model takes several seconds?

In that case I would try to split the model creation into two parts:

  • create the minimal part that is needed so that the UI can be shown. This should be done in the EDT (because the user has to wait for the completion of this part anyway - before the UI is shown he cannot interact with it)
  • do the remaining, long running parts in a background thread.

What if this cannot be done? (i.e. the UI cannot be displayed until the model is fully initialized)

In this case the user has to wait for the complete initialization of the model before he can see and use the UI anyway. So it doesn't matter whether this initialization runs on the EDT or the main thread. So use the simpler solution: everything on the EDT.

But give the user some hint that your application is starting by showing a splash screen

Insurrectionary answered 12/3, 2021 at 12:21 Comment(1)
So the takeaway should be that although you could spread the work between the Main and ED Threads, doing it all on the EDT is much better practice as it should be the "main thread" of your Swing app (you'll avoid complexity without having to deal with multithreading and you'll be sure to update your UI from the EDT). Thank you very much!!Aleda

© 2022 - 2024 — McMap. All rights reserved.