I read that all the code which constructs Swing components and handles Events must be run by the Event Dispatch Thread. I understand how this is accomplished by using the SwingUtilities.invokeLater()
method. Consider the following code where the GUI initialization is done in the main
method itself
public class GridBagLayoutTester extends JPanel implements ActionListener {
public GridBagLayoutTester() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
JButton button = new JButton("Testing");
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.anchor = GridBagConstraints.WEST;
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridwidth = 1;
button.addActionListener(this);
add(button, gbc);
}
public void actionPerformed(ActionEvent e) {
System.out.println("event handler code");
}
public static void main(String[] args) {
JFrame frame = new JFrame("GridBagLayoutDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container contentPane = frame.getContentPane();
contentPane.setLayout(new BorderLayout());
contentPane.add(new GridBagLayoutTester(), BorderLayout.CENTER);
frame.setSize(800, 600);
frame.pack();
frame.setVisible(true);
System.out.println("Exiting");
}
}
How is it that this code works perfectly ? We are constructing JFrame
and calling a host of other methods in the main thread. I do not understand where exactly the EDT is coming into picture here (what code is it executing ?). The constructor of the GridBagLayoutTester
class is also being called from the main
method which means the EDT is not running it.
In short
Swing event handling code runs on a special thread known as the event dispatch thread. Most code that invokes Swing methods also runs on this thread. This is necessary because most Swing object methods are not "thread safe": invoking them from multiple threads risks thread interference or memory consistency errors.
The event dispatching thread (EDT) is a background thread used in Java to process events from the Abstract Window Toolkit (AWT) graphical user interface event queue.
An invokeLater() method is a static method of the SwingUtilities class and it can be used to perform a task asynchronously in the AWT Event dispatcher thread. The SwingUtilities. invokeLater() method works like SwingUtilities. invokeAndWait() except that it puts the request on the event queue and returns immediately.
SwingUtilities class has two useful function to help with GUI rendering task: 1) invokeLater(Runnable):Causes doRun. run() to be executed asynchronously on the AWT event dispatching thread(EDT). This will happen after all pending AWT events have been processed, as is described above.
The code works perfectly because you are constructing the frame in the main thread, before the EDT has an opportunity to interact with it. Technically, you shouldn't do this ever, but technically you can under this specific circumstance because you cannot interact with the JFrame until it becomes visible.
The main point to know is that Swing components are not thread safe. This means that they cannot be modified from more than one thread at the same time. This is solved by ensuring that all modifications come from the EDT.
The EDT is a thread that's dedicated to user interaction. Any events generated from the user are always run on the EDT. Any user interface updates run on the EDT. For example, when you call Component.repaint()
, you can call this from any thread. This simply sets a flag to mark the component as needing a paint, and the EDT does it on its next cycle.
The EDT is started automatically and is tied quite closely into the system implementation. It is handled well within the JVM. Typically, it correlates to a single thread in the windowing system that handles user interaction. Of course, this is quite implementation-dependent. The nice thing is that you don't have to worry about this. You just have to know - if you interact with any Swing components, do it on the EDT.
Likewise, there is one other thing that's important. If you are going to do any long-duration processing or blocking for an external resource, and you are going to do it in response to an event generated by the user, you have to schedule this to run in its own thread off the EDT. If you fail to do this, you will cause the user interface to block while it waits for the long-duration processing to run. Excellent examples are loading from files, reading from a database, or interacting with the network. You can test to see if you are on the EDT (useful for creating neutral methods which can be called from any thread) with the SwingUtilities.isEventDispatchThread()
method.
Here are two snippets of code which I use quite frequently when writing Swing programming dealing with the EDT:
void executeOffEDT() { if (SwingUtilities.isEventDispatchThread()) { Runnable r = new Runnable() { @Override public void run() { OutsideClass.this.executeOffEDTInternal(); } }; new Thread(r).start(); } else { this.executeOffEDTInternal(); } } void executeOnEDT() { if (SwingUtilities.isEventDispatchThread()) { this.executeOnEDTInternal(); } else { Runnable r = new Runnable() { @Override public void run() { OutsideClass.this.executeOnEDTInternal(); } }; SwingUtilities.invokeLater(r); } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With