I'm totally fresh about threading and GUIs, therefore I couldn't figure out exactly where to call this EventQueue.invokeLater() method.
Am I supposed to call it in every event listeners and something else? What are those "things" to call this method? If so, is there any alternative way to call-once-apply-everywhere method so that It won't take bunch of lines to tuck them to the Event dispatch thread?
Thank you.
therefore I couldn't figure out exactly where to call this EventQueue.invokeLater() method.
Swing components need to be updated on the EDT so you would only use invokeLater(...) if you have code executing in a separate Thread and you want to update a GUI component.
Read the section from the Swing tutorial on Concurrency for more information.
As a general rule, unless you are using Threads, you only need to use this method when you create your GUI. Take a look at the FrameDemo from the section in the Swing tutorial on How to Make Frames for a simple example to get you started.
Am I supposed to call it in every event listeners?
No!
All code in an event handler already executes on the Event Dispatch Thread (EDT)so you don't need to invoke this method.
Swing is not thread safe. Which means that all interactions with Swing objects should be done via the event thread. Swing does this internally as well, so any time Swing calls an event listener, this will be done on the event thread.
This means two things, firstly, if you ever need to interact with a Swing object, your code should be invoked on the event dispatcher thread.
Also, it means that if you have any code in your event listeners that will run for any noticeable period of time, should be invoked on another thread from your listeners. If you do not do this, then your UI will appear frozen. A SwingWorker object can help with this.
To answer your question about needing to check EventQueue.isDispatchThread() that you asked in the some of existing answers' comments:
No, you don't have to check if you are already on the EDT before calling invokeLater().
The SwingUtilities JavaDoc states:
If invokeLater is called from the event dispatching thread -- for example, from a JButton's ActionListener -- the doRun.run() will still be deferred until all pending events have been processed. Note that if the doRun.run() throws an uncaught exception the event dispatching thread will unwind (not the current thread).
Below is further explanation of invokeLater() use.
Notice in ButtonDemo.java that createAndShowGUI() is called using invokeLater(). We must do this because the main() method is not running on the EDT (Event Dispatch Thread). main() is running on its own special main thread that every Java app has.
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
However in actionPerformed(), the invokeLater() method is not used because here we already on the EDT.
//b1, b2, and b3 are all JButtons
public void actionPerformed(ActionEvent e) {
if ("disable".equals(e.getActionCommand())) {
b2.setEnabled(false);
b1.setEnabled(false);
b3.setEnabled(true);
} else {
b2.setEnabled(true);
b1.setEnabled(true);
b3.setEnabled(false);
}
}
As far as I can recall, Event Listener methods such as actionPerformed() are always called from the EDT. (Sorry I don't know supporting documentation off-hand, and I don't have enough reputation yet to post anymore links anyway. Along with reading the pages linked in camickr's answer, try Google searching for "java tutorial swing introduction event listeners".)
So if you are trying to update a Swing component from a thread other than the EDT, call invokeLater(). If you are in an Event Listener method (i.e. already on the EDT), you don't need to call invokeLater().
Related
I have three questions which are closely related in that they are born out of each other and represent a train of thought, so I am posting them under one question. It would not help me construct the big picture of my question if I posted them separately.
1) Could you please explain in simple language what SwingUtilities.invokeLater does? I understand threading, dare I say quite a bit, but still the language of the documentation confuses me. It says:
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.
If I put some effort in to make sense of what that says, I think here is what it says, but I couldn't be so sure about it. I think it says:
The invokeLater method schedules the main window creation and the setting up of its dispatcher / message pump on the primary thread of the application only and not on a separate thread. It does it by posting the message to create the window and set it up on the main / primary application thread. In other words, the main thread is saying to us, "The window you are asking me to create will be created after I am done doing everything else that is on my plate right now."
But then two things confuses me, which I list as the two questions below.
2) Then why do I need to implement the new window's message loop as a Runnable. This implies that I want a separate thread to execute that message loop.
3) I printed out the current thread Id's in the function that creates the window and the function that is the window's message loop, and they are both different threads. So, each window in Swing runs on its own thread? That is insane. Can you please explain to me what is happening here? And also if you could please explain in a paragraph or two the threading model of GUI applications created in Swing?
public static void main(String[] args) {
SwingUtilities.invokeLater(new MainWindowEventLoop());
System.out.println(String.format("Main thread %1$d started.",
Thread.currentThread().getId()));
}
public class MainWindowEventLoop implements Runnable {
#Override
public void run() {
JFrame mainWindow = new MainWindow("Main Window");
System.out.println(String.format("Main window loop running on thread %1$d.",
Thread.currentThread().getId()));
}
}
Output:
Main thread 1 started.
Main window loop running on thread 14.
It's a little complicated, but Swing is not thread safe. To run the GUI asynchronously and safely, Sun/Oracle uses a locking pattern called Ad-Hoc Thread Confinement. All Swing components must run on the AWT EDT (Event Dispatch Thread) or the result is not thread safe.
Here's a link to Oracle's tutorial. Try to read all of those sections, see if it makes more sense.
https://docs.oracle.com/javase/tutorial/uiswing/concurrency/
Each window does NOT run on its own separate thread. There is only one EDT. Each windows runs on the SAME thread, the EDT. Each Runnable you send to the EDT is executed sequentially, one after the other, when the EDT has the opportunity to do so. Hence the "later" part of invokeLater().
Basically all the swing windows are bounded to main thread. Every single component in swing runs as thread. After the completion of an event control again returns back to main thread which waits for an event to occur.
I'm attempting to add a fancy InfiniteProgressPanel as a GlassPane for my big Swing program. However, it does not appear. It looks similar to this:
...
InfiniteProgressPanel glassPane = new InfiniteProgressPanel();
setGlassPane(glassPane);
...
glassPane.start();
doSomeStuff();
glassPane.stop();
...
I believe it is running in the same thread as the long process it is meant to cover up. I'll admit, I don't know nearly enough about threads, and I should probably figure out how to run that InfiniteProgressPanel GlassPane in a separate thread, and the long process in its own thread, too.
Be sure to:
Run all long running code in a background thread. This is a must.
Sounds great! How do I do so? Encapsulate all of the long-running code inside of an .invokeLater method? And should that be SwingUtilities.invokeLater or EventQueue.invokeLater? And what's the difference, anyway?
No, by using SwingUtilities.invokeLater(new MyRunnable) you're doing exactly the opposite -- you're guaranteeing that the long-running code will be called on the Swing event thread -- the exact opposite of what you want. Instead use a SwingWorker's doInBackground() method to run the long-running code. Regarding your second point, there's no difference whatsoever between SwingUtilities.invokeLater and EventQueue.invokeLater.
Make most all Swing calls on the Swing event thread, also a must.
Fantastic! Again, how do I do so? Same thing as above?
By using SwingUtilities.invokeLater(new MyRunnable) as noted above, or if you're using a SwingWorker then use its publish/process method pair as the SwingWorker tutorial will show you.
Call setVisible(true) on your glass pane since per the JRootPane API, all glasspanes are by default invisible.
Romain Guy's InfiniteProgressPanel doesn't seem to need a setVisible(true). It appears when the InfiniteProgressPanel.start() method is called.
I am not familiar with this, do you have a link?
Threads are different processes in the same program, per se.
In java, there are many different thread types, and the one you need for this job is SwingWorker.
The definition/use of this, from Oracle's docs, is:
When a Swing program needs to execute a long-running task, it usually uses one of the worker threads, also known as the background threads. Each task running on a worker thread is represented by an instance of javax.swing.SwingWorker. SwingWorker itself is an abstract class; you must define a subclass in order to create a SwingWorker object; anonymous inner classes are often useful for creating very simple SwingWorker objects.
As you can see, this is what you need; a background thread.
final InfiniteProgressPanel glassPane;
...
class GlassPaneHandler extends SwingWorker<String, Object> {
#Override
public String doInBackground() {
glassPane.start();
return setUpPaneAndStuff();
}
#Override
protected void done() {
try {
glassPane.stop();
} catch (Exception e) { } //ignore
}
private void setUpPaneAndStuff() {
//code
}
}
...
(new GlassPaneHandler()).execute(); //place this in your code where you want to initiate the pane
for more see:http://docs.oracle.com/javase/8/docs/api/javax/swing/SwingWorker.html
When you are updating a swing UI you need to do it in Swing's Event Thread. This includes creation of components or any sort of progress updates. You can do this via the SwingUtilities.invokeLater(Runnable) method.
Therefore, you should create the glasspane and show it via the invokeLater if in a background thread. Any progress updates to the glasspane from your long running process thread should be done via the invokeLater.
I recently found an example code:
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
The createAndShowGUI() method opens a user interface window. Then I tried to trim the code as the following:
public static void main(String[] args) {
createAndShowGUI();
}
Both versions work equally well. What is the difference?
99% of the time either code will work.
However, Swing was designed such that all updates to Swing components should be done on the Event Dispatch Thread (EDT). Read the Swing tutorial on Concurrency for more information.
The problem is the 1% of the time when it might not work. You don't want to waste time trying to debug random problems.
SwingUtilities.invokeLater ensures that the code executes on the Event Dispatch Thread (EDT). Swing is single-threaded, all component instantiation and display should happen on the EDT. Things might seem to work otherwise, but you'll possibly run into issues.
Swing has single threaded Event Loop based design and is not thread safe, with only thread safe part being a set of invokeXXX() methods used to transfer control to the Swing event loop.
Your "broken" code works just fine because nothing else is trying to touch the same part of Swing data structures from within the Event Loop at the same time.
The "main" thread started by the JVM is not the Event Dispatch Thread.
from The Event Dispatch Thread
Some Swing component methods are labelled "thread safe" in the API specification; these can be safely invoked from any thread. All other Swing component methods must be invoked from the event dispatch thread. Programs that ignore this rule may function correctly most of the time, but are subject to unpredictable errors that are difficult to reproduce.
I was looking at some example code of GUIs in Java, and I was wondering what the proper way to display a GUI. Suppose a createAndShowGUI() method is written for some GUI. I saw something like this:
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
Would it be wrong simply to call createAndShowGUI() at the end of the main method without the javax.swing stuff? Or I guess my real question is about what is going on here. I'm familiar with threads but I am not sure why it's necessary to make a new thread (is that what's going on here?) to display the GUI.
All interactions with the UI (Swing or AWT) MUST be executed from within the context of the Event Dispatching Thread.
Swing (and AWT) components are not thread safe, changing any of them from any thread other the EDT can lead to corrupted updates, paint artifices, dead locks and possibly crash the VM. They are also notoriously difficult to debug.
You might like to have a read through
The Event Dispatch Thread
The Single Thread Rule in Swing
Will the real Swing Single Threading Rule please stand up?
I should also add, when the main method is executed, it is running in what ever thread the VM created for it. This is guaranteed not to be the EDT, as it will not have begin started until it is needed.
This is why good Swing programs always start with something like EventQueue.invokeLater. You could also use SwingUtilities.invokeLater, but it's generally the same thing.
Because everything related to a GUI should be done through the Event Dispatch Thread (EDT), that is how Java manages the whole drawing of interfaces. Basically the method delegates the execution of the run() method of the passed Runnable object to the correct thread.
Mind that Runnable is not a Thread, it's just an interface to provide a method that does something (hence the class is runnable). But there is no thread involved here, the fact that Thread extends from Runnable is just because a thread is also a Runnable object in the sense that can execute something.
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new NewJFrame().setVisible(true);
}
});
Please tell me what does the above code does actually. I am looking for line by line explanation. especially the first line and tell me why do we use that and in what scenarios we have to use this.
In this Example you see an anyonmous class that derives from Runnable. This anonymous class overrides the run method of the interface runnable. Then this anonymous class is instantiated and passed to the EventQueue.invokeLater method, which is a static method. This method appends the object into... well... the eventQueue. In the EvenQueue are many events, like keyboard events or mouse events or whatever. There is a Thread that continuesly polls data from this queue. Once that Thread reaches the anonymous class that was instantiated here, it will execute the run() method, which will instantiate an Object of class NewJFrame and set it to be visible.
The whole point of doing this this complicated is that the new JFrame().setVisible(true) part is not executed in the main thread, but in the event dispatching thread. In Swing you must execute all code that modifies the user interface in the event dispatching thread.
Single-Thread-Model and EDT
Most modern UI libraries adopt the single-thread-model. That means, all the manipulation upon UI components MUST be done on the same single thread. Why? That's because allowing UI components being updated from multiple threads will lead to chaos since most Swing object methods are not "thread safe". For simplicity, efficiency and robustness, single-thread-model is adopted.
In Swing, the very thread that serve the single-thread-model is called the Event Dispatching Thread, i.e. EDT. It is not provided by Swing. It is provided by Abstract Window Toolkit, i.e. AWT.
Worker thread vs UI thread
A non-trivial GUI application usually has many threads. In modern GUI application, there can be many worker threads to do dirty work, but there's only one UI thread (Swing calls it EDT) to update the GUI. Worker threads usually need to reflect their work progress in GUI, so they need to communicate with the UI thread about that. So how does this communication happen?
java.awt.EventQueue
The communication happens through a message queue model. The java.awt.EventQueue is the very class that provides a event queue globally. This global event queue serves as the communication channel to the EDT. EDT picks up messages from this EventQueue and update UI components accordingly. If some other part of your program wants to manipulate the UI, that part of code should call EventQueue.invokeLater() or EventQueue.invokeAndWait() to queue a message into EventQueue. EDT will process all the pending messages in the EventQueue and eventually get to the message.
the main thread
Your code snippet usually resides in the main() thread, the main thread can be viewed as some kind of a worker thread here. Only that instead of updating the GUI by posting messages to EventQueue, it initiates the GUI. Anyway, initiation can be viewed as a kind of work, too.
After the GUI is initiated, the main thread will exits and the EDT will prevent the process from exiting.
And another good explanation:
Java Event-Dispatching Thread explanation
An interesting article:
Multi-threaded toolkit, a failed dream?
This is a block of code that is instructed to execute at a later time (sometimes called a deferred). The inner class (new Runnable() {...}) is essentially allowing you to pass a block of code that will be run. The invokeLater method guarantees that the block of code will be run, but makes no guarantees of when. Sometimes it's not safe to have certain code run immediately, and its too verbose to do the multi-threading yourself. So Java provides this utility method to safely run the code. The code will be run very soon, but not until it's safe to do so.
The invokeLater call will put the specified runnable on a queue to be processed later. That is, the code inside the run() method will not have been run yet when the invokeLater method call returns.
There are two typical use-cases for this type of code.
The currently executing code is run in a background thread. Background threads cannot access most of the swing API. Read more here for the reason for this. If the current thread is already the UI thread there is no reason and the call can safely be removed.
The current block must be exited, ie the code reach the last brace. This may cause resources to be released and so on. This is not so common.
An anonymous class is passed as parameter to the invokeLater call. It is the same as this code.
private void foo()
{
java.awt.EventQueue.invokeLater(new JFrameCreator());
}
private class JFrameCreator implements Runnable
{
public void run() {
new NewJFrame().setVisible(true);
}
}
Source
The invokeLater() method takes a Runnable object as its parameter. It sends that object to the event-dispatching thread, which executes the run() method. This is why it's always safe for the run() method to execute Swing code.
-IvarD