How to utilize SwingWorker and/or Timer? - java

I have been working on a program and am currently trying to resolve an issue. The program's purpose is to read through records from a database, pull information upon a certain trigger, and then display that information the GUI. The problem here is getting that data from the database to appear in the GUI, allow for some time for it to be represented on the screen, and then do the same for the next one and loop through.
I can get the data and put it on screen in the GUI, but my problem lies within allowing for that pause.
I have tried Thread.sleep but I have read that it is discouraged to do so.
What seems to be recommended is utilizing SwingWorker and/or Timer. I have spent a good amount of time studying these two but I am having difficulty fully understanding it and being able to apply it to my program. Given my problem and my program's purpose, can anyone help explain the significance of SwingWorker and Timer?

Timer executes in the EDT and the SwingWorker makes work in another threads. I really like this example Swing Worker example
Note that the Swing timer's task is performed in the event dispatch
thread. This means that the task can safely manipulate components, but
it also means that the task should execute quickly. If the task might
take a while to execute, then consider using a SwingWorker instead of
or in addition to the timer.

Caveats:
All interactions with the UI, updates, creates, should be done from within the context of the Event Dispatching Thread.
javax.swing.Timer
The Swing Timer is a special timer that allows you to setup a periodical callback that is guaranteed to execute within the context of the EDT
SwingWorker
SwingWorker is solution desinged to make a UI developers life easier by providing the mechanisms for running code in the background while providing easy (at least easier) mechanisms for synchronizing updates to the UI within the EDT.
For your problem, I would recommend the use of the SwingWorker, as you can pause in the background without effecting the UI's responsiveness
SwingWorker worker = new SwingWorker<Object, Object> {
public void doInBackground() throws Exception {
while (!loadingDone) {
Object data = loadMoreData();
publish(data);
}
// This only matter if you actually care about the result
// of what has being processed here...
return null;
}
public void process(List<Object> chunks) {
// Now in the UI...
}
}
Check out...
SwingWorker JavaDocs
Worker Threads and SwingWorker
For more details...

Related

JFrame Will Not Close

At the moment, I am working on a version of Conway's Game of Life for my own amusement. Up to this point, everything has gone smoothly, but just as I was testing some of the final parts, I noticed an irritating error. The main body of the code takes place inside of a while loop that is controlled by the number of 'generations' of the game the user would like see. While this loop is executing, the JFrame's red X refuses to respond and I am at a loss as to why this is.
Area where I am encountering this issue:
public void run(int steps) throws InterruptedException{
int a = 0;
do{
step();
myDisp.update(myDisp.getGraphics());
Thread.sleep(delay);
a++;
}while(a < steps);
}
I would suggest you to put this kind of processing in a separate thread.
As long as you keep it in the main body of your code, Swing components will not respond to any user interaction as long as the loop is running.
In this page you can find some good practices regarding asynchronous operations in Swing applications. I would like to highlight one of the topics:
Rule #2: do not run time-consuming operations on the event thread.
I'll keep repeating this: Swing uses a single thread for all GUI events. If your event handler is uploading a multi-megabyte file across the net, those events will be delayed until you're done. There is a balancing act involved with this rule: some operations (such as getting the size of a file) are so fast that they won't interrupt the user. However, that's not a reason to be cavalier, because some day your user will be getting the size of a file that resides on a fileserver that has an intermittent network connection.
This other page also shows an example of how to handle long-running tasks in a Swing application. You may also want to have a look at the SwingWorker class.
By default your while loop will be executing on the Event Dispatch Thread (EDT), which handles all GUI operations. You should never execute long running tasks on the EDT for this reason - the GUI will lock up, since you're not giving it any free time to handle user input! However, you must execute any code that touches the GUI on the EDT. There's a special method, SwingUtilities.invokeLater(), that will do this (take a Runnable and invoke it on the EDT.)
So in your example you would create a new thread and execute it, this thread would contain your while loop, and the myDisp.update() call would be wrapped in the above method to ensure it was still on the EDT. The alternative (neater) solution is to use a SwingWorker, which provides a nicer interface for accomplishing the same thing.
Your long-running while loop is running on the Swing Event Dispatch Thread or EDT, typing it up, and preventing all Swing graphics and user interactions. Solution: use a background thread for your long-running tasks.
Please read: Lesson: Concurrency in Swing
for more details on this and for how to use a SwingWorker.

eli5 swing worker and swing thread

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.

SwingUtilities.invokeLater on full speed thread

I have a thread that does display updates on my JFrame by using SwingUtilities.invokeLater. The thread's speed is adjustable, and when it set to full speed (no sleeping between updates), my program gets slowed down badly. I guess the problem is my thread is generating too much SwingUtilities.invokeLater events that JFrame's thread can not consume. So is there anything I can do on my thread to remove previously added but not consumed events? Or should I use some other ways to update JFrame without using SwingUtilities.invokeLater?
Thanks in advance.
This might be a perfect job for SwingWorker. You can publish incremental updates, and SwingWorker will batch them to solve the performance problem:
Because the process method is invoked asynchronously on the Event Dispatch Thread multiple invocations to the publish method might occur before the process method is executed. For performance purposes all these invocations are coalesced into one invocation with concatenated arguments.
The code you want to run on the EDT, you add by implementing process(). The list of updates is passed to you in the argument.
It sounds like you want to avoid saturating the event dispatch thread. The class javax.swing.Timer, discussed in How to Use Swing Timers, includes setCoalesce(), which "coalesces multiple pending ActionEvent firings." It may an alternative way to pace your updates.
As mentioned here, SwingWorker is limited to 33 Hz.
Can you use a simple repaint()? The advantage of that is that multiple calls are merged into one.
(Elaboration added)
Let's say you are constantly updating your GPS location and displaying it in two text fields. Your thread to do the updating:
run() {
while (keepGoing) {
Point myLocation = computeMyLocation();
locationModel.setLocation(myLocation);
locationComponent.repaint();
}
}
then, in MyLocationComponent
#Override
public void paintComponent(Graphics g) {
Point myLocation = locationModel.getLocation();
// you'd really want a NumberFormat
latitudeTextArea.setText(String.valueOf(myLocation.y));
longitudeTextArea.setText(String.valueOf(myLocation.x));
super.paintComponent(g);
}
The advantage is that this splits the model from the view (if you think of the thread as the controller, this is MVC), and all the threading should work - no need for any invokeLater(). One disadvantage is that your thread needs to know all of the JComponents that need to be updated. In a "real" scenario you'd probably fire events to listeners that trigger the repaints, either from the "controller" (your thread) or from the model.
NOTE: As pointed out by #trashgod, in LocationModel, the getLocation() and setLocation() methods should be synchronized so that updates appear immediately.

Sleeping in a SwingWorker?

I need to feed test data to a Swing interval over a time period. The data set is long to parse, so I'm using a SwingWorker to parse it in the background. When it comes to feeding the data to the GUI (say, one item per second), I could start a Timer from the SwingWorker, but this seems overkill. Any reasons not to sleep from within the SwingWorker itself?
Cheers
Since SwingWorker doesn't run on the EDT, sleeping within is perfectly fine.
SwingWorker is designed for situations
where you need to have a long running
task run in a background thread and
provide updates to the UI either when
done, or while processing.
In my opinion, a Timer in addition to a SwingWorker would be overkill. Instead, just publish the parsed test data whenever possible, even at irregular intervals.
While you make the SwingWorker sleep it will not be loading data. If that is desired then this approach is fine.
If you want to keep loading the data and just pace the feeding to the GUI then it seems like a better design would be to start a Timer in the GUI that would check and pull new data from the worker at an interval, instead of the worker having to make invokeLater calls back to the GUI.

SwingUtilities.invokeLater() why is it needed?

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.

Categories