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
Related
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.
So I have seen countless different GUI tutorials, and all of them have said to use this code:
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
And although I may not quite understand what this exactly does, since I'm somewhat new to GUI, I do understand the basics of what it does... or so I thought. But then I, as an experiment, cut it all out, and just left:
public static void main(String[] args) {
createAndShowGUI();
}
And it appeared to work. So now I have a question: what is the purpose of keeping the first piece of code I had, rather than just using the second, when it seemed like the second worked just as fine? If it is necessary, what will happen if I don't use it?
In short, yes, it is necessary whenever you make changes to any Swing object (unless the API says they are thread safe).
Any changes you make to the GUI must be made on the Event Dispatch Thread (EDT) because the Swing objects are not thread safe. From the Event Dispatch Thread Tutorial
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. 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.
Calling SwingUtilities.invokeLater ensures that the code int he runnable is invoked on the EDT and you don't get weird errors. That is why when you removed that code it looks like everything is working, because in the situations you tested it probably did. But it might not always and you don't want to have code that works sometimes or has timing issues.
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.
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);
}
});
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(...); }
});