smeeb
smeeb

Reputation: 29577

What to put (and not to put) inside SwingUtilities.invokeLater?

It seems to be a common/good practice in Swing-land to call SwingUtilities.invokeLater(Runnable) from inside your static main method:

public class MyApp extends JFrame {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            void run() {
                // What to do here?!?
            }
        });

        // And what to do here?!?
    }
}

According to that method's JavaDocs:

Causes doRun.run() to be executed asynchronously on the AWT event dispatching thread. This will happen after all pending AWT events have been processed. This method should be used when an application thread needs to update the GUI. In the following example the invokeLater call queues the Runnable object doHelloWorld on the event dispatching thread and then prints a message.

But even after reading this, I'm still confused about what (specifically) code to put inside this Runnable (that we pass to invokeLater), and what code to not put inside of it. Any ideas?

Upvotes: 0

Views: 1816

Answers (2)

smeeb
smeeb

Reputation: 29577

For future comers, I figured it out, even though the docs don't really explain this in a way that is obvious to Swing newbies:

  • When the docs or blogs/articles/people say "Anything that touches the UI", this translates to: "Any manipulation of a Swing class under javax.swing.*". Hence, doing anything with JFrame, JPanel, or any of the JComponents. All this stuff should be executed inside the Runnable you pass to SwingUtilities.invokeLater from inside your app's main method. So basically you end up with one gigantic, monolithic Runnable that does all UI code manipulation. Strange and anti-MVC IMHO.
  • If you have a long running process you should strip all the Swing code out of that process and pass it into your own SwingWorker

Upvotes: 1

MadProgrammer
MadProgrammer

Reputation: 347332

I think camickr has basically answered the core concerns

To (mostly) re-iterate, in goes in anything that might alter the UI or interact with the UI in some way, directly or indirectly, outside can go anything else, especially any blocking or long running code

If you've seen any of my Swing related answers, you would have seen this kind of template (and yes, it's a code template I have setup in Netbeans)

import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

}

can you give a few concrete examples?

If it could potentially alter the UI in anyway (directly or indirectly - change a property of a component, update the layout, etc). The general rule of thumb, is treat any Swing based component as NOT thread safe and you shouldn't have any issues, start second guessing this rule and you will run into trouble, maybe not today, but most likely tomorrow.

The problem is, there's very little guarantee in the API when a component might trigger an update to the EDT, which is what you're really concerned about. When in doubt, put in the EDT.

There are very few methods in the API which are considered thread-safe, repaint is the most obvious, but personally, I just treat the whole API as not been thread safe, it saves a lot of guessing.

If you know you have a long running or potentially blocking operation (file IO, network calls, etc...), then these need to be made outside the EDT (maybe using a SwingWorker or Swing Timer as appropriate), but the moment you want to update the UI (change the text of a label or update a progress bar for example), these calls MUST be made within the context of the EDT.

Start by taking a closer look at Concurrency in Swing

Upvotes: 2

Related Questions