Please explain invokeAndWait() method in SwingUtilities.I am unable to understand this.
Explain it very clearly. It would be of great help if you try out with an example.
Edited to add #noob's expansion of the question:
What's not clear about this?
Here's a modified usage example:
import javax.swing.SwingUtilities;
public class InvokeAndWaitStuff
{
public static void main(String[] args)
{
final Runnable doHelloWorld = new Runnable() {
public void run() {
System.out.println("Hello World on " + Thread.currentThread());
}
};
Thread appThread = new Thread() {
public void run() {
try {
SwingUtilities.invokeAndWait(doHelloWorld);
}
catch (Exception e) {
e.printStackTrace();
}
System.out.println("Finished on " + Thread.currentThread());
}
};
appThread.start();
}
}
Output:
Hello World on Thread[AWT-EventQueue-0,6,main]
Finished on Thread[Thread-0,5,main]
And why is this important?:
Causes doHelloWorld.run() to be
executed synchronously on the AWT
event dispatching thread. This call
blocks until all pending AWT events
have been processed and (then)
doHelloWorld.run() returns. This
method should be used when an
application thread needs to update the
GUI.
As far as I can tell, this is basically a bottleneck that forces GUI updates to be executed synchronously by a single thread, rather than asynchronously by multiple threads, which can potentially be unsafe.
To understand what invokeAndWait() does, you first need to understand the event/thread model of Swing.
Basically, everything that affects the GUI in any way must happen on a single thread. This is because experience shows that a multi-threaded GUI is impossible to get right.
In Swing, this special GUI thread is called the Event Dispatch Thread, or EDT. It is started as soon as a Swing top-level component is displayed, and it's bascially a worker thread that has a FIFO queue of event objects that it executes one after another.
When a Swing GUI needs to be drawn or updated, the JRE places an event on the EDT queue. User actions that cause listeners to be called start as events on the EDT queue. And (this is this is the important part) everything your program does that changes the GUI (like registering listeners, adding/removing GUI components or changing model data that the GUI displays) must be placed in the EDT queue, or the GUI can get corrupted.
And now for the finish: invokeAndWait() places the Runnable you pass to it into the EDT event queue and waits until the EDT has executed it. This should be used when a non-GUI thread needs to do something that affects the GUI, but also needs to wait until it is actually done before it can continue. If you just want to do something that affects the GUI but do not care when it is finished, you should instead use invokeLater().
I had a similar problem in a JTable. The program was blocked somewhere in "scrollRectToVisible" method. I have replaced the call by wrapping it in an invokeLater call.
The invokeAndWait did not resolve my block problem.
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
table.scrollRectToVisible(r);
}
});
Related
I have some trouble with my java swing program. I try to stop my main Frame thread when the ExportWithoutEntryPointFrm Frame appears in an own thread.
I implemented that with java.util.concurrent.Semaphore.
The appearing Frame shows only an empty Frame, the buttons, lables and so on won´t be shown and both threads are blocked. I think there is a deadlock but I don´t find it.
My code for the new warning Frame, which will be called from the main Frame:
public class ExportWithoutEntryPointFrm extends javax.swing.JFrame implements Runnable
{
private Semaphore sema;
private boolean decision = false;
public ExportWithoutEntryPointFrm(Semaphore semaphore)
{
initComponents();
this.setLocationRelativeTo(null);
this.sema = semaphore;
}
#Override
public void run()
{
this.setVisible(true);
try
{
sema.acquire();
}
catch (InterruptedException e)
{
this.decision = false;
this.sema.release();
this.setVisible(false);
}
}
}
And the calling code from the main Frame:
Semaphore waitForDecisionSema = new Semaphore(1, true);
ExportWithoutEntryPointFrm warningFrm = new ExportWithoutEntryPointFrm(waitForDecisionSema);
warningFrm.run();
waitForDecisionSema.acquire();
First of all, calling a run() method of a Runnable doesn't start a new thread.
Second, even if it did, Swing components like JFrame MUST be used from the event dispatch thread only.
Third: since everything is done from a single thread, the EDT, as soon as this line is executed:
waitForDecisionSema.acquire();
the EDT is blocked waiting for some other thread to release the semaphore, and that will never happen, so the EDT is blocked forever, making your GUI unresponsive.
You seriously need to reconsider your design. But I don't know what you're trying to achieve, so it's hard to advise. Given the name of your semaphore, I think that what you're looking for is a modal JDialog, that would prevent the user to use the parent frame of the dialog until the dialog is closed.
I try to stop my main Frame thread when the ExportWithoutEntryPointFrm Frame appears in an own thread
Well, that's a massive contradiction in terms, Swing is a single threaded framework, you can operate components/frames/windows in separate threads, it won't work and you'll end up within no end of issues, dead locks been the most obviously.
Start by having a look at Concurrency in Swing for more details.
Now, there a number of mechanisms you can use to off load long running or blocking code to a separate thread and still interact with Swing, a Swing Timer for regular scheduled callbacks, SwingWorker for long running or potentially blocking calls, but which supports callbacks to the EDT, making it easy to use and even SwingUtilities.invokeLater for those times you have no other choice.
Have a look at How to use Swing Timers and Worker Threads and SwingWorker for more details
Based on you description though, I would suggest that what you really want, is a modal dialog, which will block the current frame/code execution at the point the dialog is made visible, but which will allow the UI to continue responding to the user.
See How to Make Dialogs for more details
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.
Can someone please explain this below written code ?
public void setSelectedFolder(final File f){
if(f != null){
Runnable r=new Runnable(){
public void run(){
target.setText(f.toString());
}
};
try {
SwingUtilities.invokeLater(r);
} catch(Exception x) {
}
}
}
It is part of Java program which allows user to select a file from a folder and split this file into chunks.
public static void invokeLater(Runnable doRun)
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.
The only thing the code does is to put target.setText(f.toString()); in the EDT to be executed there and update your TextFieldsafely. If you don't do that, you could be facing ugly bugs due to Swing not being thread-safe.
Always putting things into EDT isn't good for readability so there's the SwingWorker do that hard work with syncing all your GUI related long running tasks, but in this simple case you wouldn't need to let those SwingWorkers do the work for you, as it is a simple setter without any long waiting times.
That is for the SwingUtilies.invokeLater(), the Runnable in this case is used to have a run() method in which you define the code you wish the EDT has to execute. Normally you use Runnables to create Threads.
But that`s another big chapter, you can find a lot of information about that on the internet.
your code has wrong desing,
you have got issue with Concurency in Swing
FileIO should be wrapped inside try - catch - finally block, not invokeLater
if everything ended, then output to AWT/Swing GUI could be wrapped inside invokeLater
use SwingWorker (ev. Runnable#Thread) for this idea
How can I know, whether I should make a function call within GUI thread.
if (SwingUtilities.isEventDispatchThread()) {
// ...
} else {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
// ...
}
});
}
For example
// Should I call this within GUI thread?
jTable.getModel().setValueAt(...
Or
// Should I call this within GUI thread?
jComboBox.showPopup();
As I know, making operation in incorrect thread, may yield problem which is not easy to be detected. Hence, quite difficult for me to verify whether I am doing the correct stuff.
Currently, what I am doing is, If I am not sure, I will just call them in GUI thread
Not sure whether this is the best way, or there is a reliable way to figure out?
If you really need some ultra-generic thing "invoke ASAP" functionality, a helper like this is useful:
void invokeAsSoonAsPossible(Runnable action) {
if (SwingUtilities.isEventDispatchThread())
action.run();
else SwingUtilities.invokeLater(action);
}
// Usage:
invokeAsSoonAsPossible(new Runnable(){
#Override
public void run() {
jTable.getModel().setValueAt(...
}
});
But my experience tells me that it's a far better strategy to structure and document your code so that it gets easier to keep track of what is running where. If you've got a public method in a class which should be run on the EDT, JavaDoc is a good friend:
/**
* Blah blah blah, describe the method's purpose.
* <p>
* <strong>Note:</strong> This method should always be
* invoked on the Swing event dispatch thread.
*/
public Pony calulateValue() {
// go ahead and touch the components any way you please
}
You can also add an assertion in EDT-only methods as a kind of executable documentation:
assert SwingUtilities.isEventDispatchThread();
In short: If you have a hard time keeping track of which thread you're in, your code is probably so crufty that you have a hard time keeping track of anything, and you should worry about refactoring your code, not which thread you're on.
Actually
if (SwingUtilities.isEventDispatchThread()) {
// just do it, you're already in EDT
} else {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
// ...
}
});
}
All the code that involves Swing or AWT components/classes should be run in the EDT, ie. using SwingUtilities.invokeLater(Runnable) helper.
You can configure your app using Substance Look&Feel for testing purposes. It throws an exception if UI related code is run outside of EDT.
Almost all Swing methods needs to be executed on the UI thread. There are a few exceptions (such as some setMethods). These exceptions are documented in the API docs (usually says something like "this method is thread safe"). The general rule however, is that all GUI updates should take place on the UI thread.
In most situations you should know which thread you're currently in. It's ofter quite easy to tell. All call-backs triggered by GUI events are executed on the UI thread, and the actions in the main thread and all other threads you've started are not on the UI thread.
If you however do call code from your own threads sometimes and from the UI thread other times, you could, as you've shown in your question, determine if you're on the UI thread by calling EventQueue.isDispatchThread().
I would put the code to be executed in a separate method, updateGuiComponent(...) and do
if (EventQueue.isDispatchThread())
updateGuiComponent(...);
else
SwingUtilities.invokeLater(new Runnable() { // or invokeAndWait
public void run() { updateGuiComponent(...); }
});
I have a little app that at the moment consists of a JPanel with an "Open File" button.
Once the user clicks the button a new JFileChooser is created so the user can select a file.
Once the user selected a file, this file will be processed.
What I want to do, is to set the text on the JPanel to "Processing File" While the file is being processed.
I have all the code for this and then after the code, I call the method to actually process the file, but what happens is that it processes the file first and then update the gui components
How do I get around this?
You should process your task in another thread rather than in Event Dispatch Thread (EDT).
public void actionPerformed(ActionEvent e) {
statusLabel.setText("Processing File");
new Thread(new Runnable() {
public void run() {
// do something long task
SwingUtilities.invokeLater(new Runnable() {
public void run() {
statusLabel.setText("Done!");
}
});
}
}).start();
}
Using a Swing Worker Thread
As you've identified, processing the file means the Swing thread (which invoked this) is waiting for the processing to complete. So you need to invoke this in a separate thread.
The processing should run in parallel with other stuff (including the GUI updates). Once it's complete, it can call back on another component to signal that the GUI can update a status message (See SwingUtilities.invokeLater() and create an appropriate Runnable to do this)
You should process the file in a separate thread. This will allow you to kill two birds with one stone: First, your app will be more responsive. Second, the title change will actually happen.
OTOH, dealing with multithreading is a bit tricky. In particular, you may want to block some operations while the processing thread is running and then you need to rollback upon completion.
Keep in mind that the new thread cannot do GUI operaions directly: The non-GUI thread must use SwingUtilities.invokeLater() to ask the GUI thread to carry out operations on its behalf.