I had a program I got some help from here(how do I make my program check the stock market value every hour[java]) and I have been reading about swing worker ever since. I still have not fixed the program as I reread the official doc like 3 times and I am still a bit confused. Here is what I think I understand and please correct me if I am wrong.
You use SwingWorker when you have a long background process, and you put the SwingWorker inside your action performed? Once you create your process if you want it to update the GUI you make it return a value and you get() the value from the SwingWorker done() method. I am confused "where" to initialize SwingWorker because I want to say its the action performed, but isn't that where SwingInvokeLater is involved? if that is the case than what is the difference between the two. I believe SwingInvokeLater and done() both update your GUI by being run on the EDT.
I feel lost just writing that all out, I feel like I am getting closer to understanding but for some reason it just wont click. I don't like the examples the official doc provides, I guess I just don't see the whole picture. The official doc said to initialize your GUI inside a SwingInvokeLater but I don't understand the difference between that and just initializing my GUI in main().
Your questions / my replies:
You use SwingWorker when you have a long background process, and you put the SwingWorker inside your action performed?
It can go inside of an ActionListener, yes. You create it and execute it where it is needed, no more, and no less.
Once you create your process if you want it to update the GUI you make it return a value and you get() the value from the SwingWorker done() method.
That's one way to update the GUI. You can also use the publish/process method pair to update the GUI with interim results. You can also use a PropertyChangeListener attached to a SwingWorker to update the GUI. No matter what, it's usually a good idea to call get() somewhere, even if nothing is returned, as this will allow your Swing GUI to become aware of any exceptions that might have been thrown during the running of your SwingWorker.
I am confused "where" to initialize SwingWorker because I want to say its the action performed, but isn't that where SwingInvokeLater is involved?
The SwingUtilities.invokeLater(...) is used to queue code onto the Swing event thread, the EDT. This is not necessary inside of an ActionListener because its code is already called on the Swing event thread.
if that is the case than what is the difference between the two.
They are completely different. Again, invokeLater(...) is to call code on the event thread, and a SwingWorker is for calling long-running code off of the event thread.
I believe SwingInvokeLater and done() both update your GUI by being run on the EDT.
Yes they both can.
The official doc said to initialize your GUI inside a SwingInvokeLater but I don't understand the difference between that and just initializing my GUI in main().
By using SwingUtilities.invokeLater(...) you guarantee that the code passed into it is run on the EDT, the Event Dispatch Thread. If you don't do this, you don't have this guarantee. While many Swing programs will run most of the time without doing this, they may (and do) sometimes fail if this care isn't taken.
Edit
So I guess I am heading in the right direction. If I have a process that checks a value every hour on a website, since its a short process(takes a second) will it be better to use invokeLater()?
You could use some type of timer for this, possibly a ScheduledExecutorService which would be run in the background of Swing, perhaps with a SwingWorker. Then the process would be called background to the Swing thread, and you can update the GUI via publish/process.
Does the entire block of code go inside invokeLater or just the updating the GUI part. I feel like the entire code should go inside invokeLater but someone told me just to update the GUI such as (text.setText()) inside invokeLater().
As mentioned, your GUI needs to start up inside of a Runnable that is passed into a call to invokeLater(...). As for while your program is running, if the background code is run using a SwingWorker then usually there is no need a call to invokeLater(...). That is one of the reasons for using a SwingWorker rather than a plain vanilla Thread.
Edit 2
You state:
one last question I just came across while testing..inside an action performed I made the buttonclick change textfield to say hi, then I put in a try catch for Thread.sleep(1000) then change textfield to say ho. How come the result only outputs ho? it doesnt show hi, I tested with numbers and can see the program locking up. I know using a thread will fix this but just wondering why it wont display the output if I put a sleep.
When you call Thread.sleep(...) you put the calling thread, here the Swing Event Dispatch Thread or EDT, to sleep. Since it is responsible for all Swing painting and user interaction, the whole application goes to sleep, and the GUI is unable to perform any updates until the sleep has completed. This is precisely why you must use a background thread to perform this sort of thing.
Related
Here is what I am trying to do:
I have a JFrame containing a JTextArea displaying updates on an on going connection. The user is supposed to be able to press the JButton to the right of it if they want to cancel the connection. However, since the connection is blocking (using) the thread while trying to connect, the GUI becomes frozen. I am looking for a quick fix. Having the ActionListener on a separate thread possibly? I do not have much experience with threads though I can make basic use of runnables.
Does the answer have something to do with using the EDT? If so how should this be implemented?
PS for clarification, the button should be able to kill a thread creating the connection. After reading it seems that an executorService. could help with this? Yes? or not at all?
It would be advisable to first get up to speed regarding Swing (or virtually any UI framework) and multi-threading. This is the napkin version:
Any modifications to the UI or reads from it (e. g. to get the value of a textfield) must be done only on the UI thread (which is also sometimes called the "Swing Thread" or "Event Dispatch Thread" (EDT)
Any blocking or long-running operations - like network communications - must NOT be run on the UI thread. Otherwise they will prevent buttons from working, texts from being updated etc.
In Java, the ExecutorService and its friends will make it relatively easy to let long-running or blocking stuff run on a background thread
If something happens on the background thread that requires you to update the UI, encapsulate the UI-related code in an EventQueue.invokeLater call. This will make sure the Runnable you pass gets executed on the UI thread.
The SwingWorker class encapsulates this logic and provides an easy to use helper for simpler cases.
When doing this the first time, it can be a bit daunting, but it pays off to understand this thoroughly, because it does not only apply to Swing, but to any other UI code, too.
for clarification, the button should be able to kill a thread creating the connection. After reading it seems that an executorService. could help with this? Yes? or not at all?
yes
while(localBooleanVariable) inside Runnable#Thread, plain Thread
by using SwingWorker.cancel()
easiest could be SwingWorker, because is cancelable and output from publish(), progress() is on EDT
I'm trying to make "Realtime Feeling JTable". I made GUI with JTable, and then there is a button named START. When I click this button, the program will call below start() method. (It's just an example). Adding row is no problem, It works well. But the problem is, rows come to Jtable just at one time. (maybe program finish start() method, The rows come up with at all together.) There is 1000 more statement in my start() method. It's not realtime feeling. I shoud wait until start method finished. and then 1000 rows added at once.
void start(){
int a = 3+3;
addRow(new String[]{"a is 6"})
int b = 4+4;
addRow(new String[]{"b is 8 "})
}
What I'm gonna do is just "Real Time Feeling", I want to see adding row one by one, not at once. Could you understand my purpose? Imagine "Fiddler" Program. you can understand easily. Can anyone help me? Should I make a Thread?
Thanks for reading, and sorry for ackward expression(english is not my language)
This is because of the way Swing threading works. There is one single thread that handles all rendering, updating, etc. Your processing of the start() method is happening inside that render thread so nothing else on the GUI will respond until you return from the method.
What you need to do is use a SwingWorker or a ThreadPoolExecutor and farm the processing off to another thread. That can then update the GUI on a regular basis as the processing continues.
http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html
Note that by doing this people can potentially click the button multiple times and call start() again before the first one has finished. You will need to consider and handle that case - for example by disabling the button until the first one completes.
Use a Swing based Timer. In the actionPerformed(..) add a new record. See How to Use Swing Timers for details.
In swing there is a thread called EDT (Event Dispatcher Thread) that is responsible for GUI to behave like a real time, user friednly app. If you interfer EDT with a long running method you will freeze your app GUI. You have to do long running tasks in background (in a thread different than EDT). You can do this by using javax.swing.SwingWorker<T,V> or javax.swing.Timer
I have read a number of articles on the internet about when something should run in the EDT, and when it shouldn't. But I'm still not sure I understand, so I'd like to ask a few question about this:
What pieces of code are going to run by default inside the EDT?
What pieces of code are going to be run be default outside the
EDT?
When should I use InvokeLater() so something that by default would
run outside the EDT, will run inside it?
When should I prevent a piece of code from running (by default) inside the EDT, by creating a new thread and putting that code inside it?
Thanks
All the code executed by an event listener.
The code in your main method, the code executed inside a thread that you explicitely started, or that has been started by the usage of a Timer or SwingWorker.
When creating a Swing GUI in your main method. Or when you want to interact with a Swing component (or its model) from inside a background thread.
When this piece of code is blocking (like long IO) or is taking more than a few milliseconds to execute. All the code executed from inside the EDT prevent this thread from doing its main job: repainting the GUI and reacting to events.
First of all thank you so much for editing and formatting your question very well. It helps a lot when answering your question.
Also i have to admit i am not 100% sure about my answers, so guys: feel free to correct me if i am wrong.
Everything which changes your graphical user interface.
Not quite sure about that.
If you need to update your gui with the time intensive calculations.
For example if you want to show the numbers from 0to 100000000 in a
JLabel.
Everything which would block your gui from user interaction because
it takes a lot of time, for example some calculations with a lot
of datasets.. But you need to make sure to access values only from
one thread or to synchronize the threads with volatile and
synchronize...
I have hundreds of different functions that run in the EDT. A great deal of them include long-running tasks and some include changes to the GUI. Occasionally the GUI hangs for users but it is hard to keep track of all the locations this happens due to the GUI hangs not happening in the same areas 100% of the time. The issue is not high priority because the hang usually starts working after a minimize/maximize of the window, but it needs to be done eventually.
After some research I discovered I could use doInBackground() under SwingWorker for any methods with labor-intesive work and use done() for GUI drawing. Also I believe I can use SwingUtilities.invokeLater for every GUI drawing that happens to be in the doInBackground() function. However, I want to avoid adjusting every one of the hundreds of functions in my code.
Is there a way I can use a single SwingWorker and send any long-running methods to the doInBackground() function? Using the invokeLater function multiple times for every misplaced GUI code where a SwingWorker would be used is not a problem as it is not that frequent.
If this is not possible is there some kind of alternative I can use? Thank you.
All methods that update the GUI must be invoked on the EDT, otherwise you may end up with some unexplained GUI behavior (which sounds like what you are seeing). You could have repaints that don't happen properly, thread races, etc.
It is not advised to run long running tasks on the GUI because they will cause the GUI to become unresponsive, so for long running tasks, SwingWorker is a good solution to use (note that the process and done methods are called on the EDT automatically so your worker can do its long running work in doInBackground but you can safely update the GUI without using SwingUtilities.invokeLater from the done method).
As you mentioned you have hundreds of methods and you don't want to call SwingUtilities.invokeLater every time, you might want to look into one of the task frameworks. The Swing Application Framework was developer under JSR-296 http://java.sun.com/developer/technicalArticles/javase/swingappfr/ but is not actively supported, but still provides a nice framework.
http://en.wikipedia.org/wiki/Swing_Application_Framework is a list of alternative frameworks.
It sounds like you are going to need to do some significant rewriting in your application. Calling GUI methods from outside the EDT is unsafe to do.
I don't see how what your asking would be possible. Swing has no way of knowing of what would qualify as a "long running" method call before execution. If the method is already being executed (on the EDT) Swing can't simply pick it up and move it to a new thread. Even if you would indicate which method calls should be run in background threads pulling it off would be hard. The only way I can think of to make this possible in Java is with AOP (you could intercept the method calls). But implementing AOP would be harder then reimplementing your existing application to use SwingWorkers.
It sounds like the architecture of your Swing application is broken. Long running tasks must not be executed on the EDT. I'm sorry but I think you just have to bite the bullet on this one. If you want your application to feel snappy, responsive and have predictable behavior you will have to fix this by putting the long running code in background threads.
If your application uses a lot of background tasks you might want to use the excellent Swing Task API. Otherwise you will find yourself in a SwingWorker spaghetti quite fast.
for every GUI drawing that happens to be in the doInBackground()
You can't call Swing drawing, updating, etc. methods in the 'doInBackground()' method (well actually you can, but you must not do that). This is because this is the method which gets executed off the EDT. GUI drawing and component updates must only be called in the 'done()' method of a SwingWorker.
Why is it necessary to put GUI update code in SwingUtilities.invokeLater()?
Why cant it be internally taken care of by Swing itself? Why does the caller have to care about how swing handles UI updates?
Swing objects are not thread safe. SwingUtilities.invokeLater() allows a task to be executed at some later point in time, as the name suggests; but more importantly, the task will be executed on the AWT event dispatch thread. When using invokeLater, the task is executed asynchronously; there's also invokeAndWait, which won't return until the task has finished executing.
Some information about the decision not to make Swing thread-safe can be found here: Multithreaded toolkits: A failed dream? [Archived]
Because GUI updates must be done in the event dispatch thread. If you're operating in a different thread, doing the update in invokeLater yanks it out of your thread and into the event thread.
More explanation here: http://www.oracle.com/technetwork/java/painting-140037.html
The smart thing to do with big updates (like repopulating a JTable from the database) on Swing is to get the underlying model, do the updates on the model in your thread, then fire off a notification using invokeLater. That keeps your gui responding to events and redrawing. If the update is going to be very extensive, you can even fire off these notifications with invokeLater at regular intervals while you're updating, like every second or two.
Swing is single-threaded. Every update to the UI must happen from the so-called EDT – the event-dispather thread which is the main GUI thread Swing (and I think AWT) uses. If you don't do this, then weird things can or will happen (though I like Windows Forms better here which just throws an exception if you do it wrong).
That being said, you don't need to wrap every single UI operation into SwingUtilities.invokeLater() – if the code you're writing is already executed by the EDT this isn't needed. So the ActionListener for a button click doesn't need this. But a listener on an external object, running in some other thread, that updates a JLabel somewhere – there you need it.
Swing was not written to be a thread safe GUI toolkit so all GUI updates should happen from a single thread to avoid any deadlocks. In Swing this is the Event Dispatcher Thread (EDT).
See Concurrent in Swing from the Java tutorial for more details. It also references this blog entry on why it is hard to write a multithreaded GUI toolkit.
All the painting of the components should be performed in a single thread, so, they are rendered properly. That way the component will know, what part has already been painted and which part hasn't.
If you invoke a "painting" related method ( paint, update, paintComponent, show, setVisible, pack etc. ) outside the EDT, you'll be trying to paint in two different threads, and that may bring problems.
When you need to use another thread to update the UI, you should invoke it with the invokeLater facility, which in turn will put it in the EDT for you, so you still paint in the same thread.
You don't need to use it, if you're coding in a method that runs in the EDT already ( for instance, actionPerformed or paint or one of those ) Or if you are executing code not UI related ( for instance, processing files in the background etc. )
To better understand all these concepts read:The single thread rule
SwingUtilities.invokeLater()
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.
...
Repeating others: Swing is not thread safe so one thread must do all the updates to avoid concurrency problems. invokeLater is an utility method to execute something inside the event processing thread.
Why doesn't Swing does it internally: this is my impression... I think because it would be overkill -to check every place where an update is taking place. It would bloat the Swing code, dificult the review and maintainability of the code.
By the other hand it's not that dificult for an application to know if it's not executing inside the GUI thread and call invokeLater. It will be when the own application launched some thread before.