Reputation: 29577
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
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:
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.SwingWorker
Upvotes: 1
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