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.
Related
I have an AnimationTimer, that I use as an infinite loop like this:
animator = new AnimationTimer(){
#Override
public void handle(long now) {
// Update
Game.simulationStep();
// Render
Game.render();
}
}
};
animator.start();
The handle function is called 60 times a second, updates a small Game and renders some views in a scenegraph.
What I´m asking myself is, if when I have Events like a button click, will the code of the event be executed after a loop iteration is done?
Or is it multithreaded?
The thing is, I have a List of GameObjects which can be manipulated by the event (removing GameObjects by button click) but also by the logic in simulationStep.
It could be problematic, if the event removes GameObjects from that List, while simulationStep() is doing something with the Objects in the List.
The answer depends not on the code you provide but on your other code.
If the code is responding to events originating in the JavaFX framework (like a button press), then you don't need to worry, because those events are also on the JavaFX thread, the same as the animation timer.
You only need to worry if the event originates on a different thread outside of JavaFX. For example, an incoming chat message from a network chat client, or an AI loop that you are running on your own thread.
Also, you shouldn't use property listeners and bindings that might change values on another thread. For example, don't modify from another thread an observable list that is used to back a list view. The internal implementation of the observer and binding features assumes that the properties and listeners are all used on a single thread. Again, that is only something to worry about if your code is actually multi-threaded.
If you do really have multi-threaded code with events originating from other threads, use JavaFX concurrency, e.g. Task and/or Platform.runLater. Possibly in conjunction with a queue as in Seph's answer as demonstrated (somewhat), by this multi-threaded JavaFX logging framework using a queue. However, usually a separate queue is not required, because Platform.runLater will add runnables to a built-in queue that JavaFX maintains for stuff to be run on the JavaFX thread later.
For your specific concern:
I have a List of GameObjects which can be manipulated by the event (removing GameObjects by button click) but also by the logic in simulationStep. It could be problematic, if the event removes GameObjects from that List, while simulationStep() is doing something with the Objects in the List.
No. It will not be problematic. Everything is running on a single thread, the GameObjects cannot be removed by button click while simulationStep() is running, because the click handler and the simulationStep cannot be running at the same time.
A good summary of different options for executing periodic events and when and when not to involve multiple threads, plus how to handle them if they are used, is in Slaw's answer to:
JavaFX periodic background task
I advise reading the JavaFX architecture overview sections on the Glass Windowing Toolkit, Threads, and Pulse (twice). The document explains how the JavaFX system works with respect to threading, event processing, and pulse handling (the AnimationTimer handle method is triggered by a pulse).
AnimationTimer is not multithreaded and the handle() method runs on the JavaFX application thread, so I guess if you put an infinite loop or a blocking call inside handle(), it freezes the application. Answering your question, unless you have some behaviour that executes on other threads, it'll work fine.
Here's a related thread: Is AnimationTimer running in its own thread?
You can add the events to a queue and process that queue first in your animation timer. This should avoid anytime of concurrency or race condition issues you may be concerned about without hurting anything if they do not actually exist.
animator = new AnimationTimer(){
#Override
public void handle(long now) {
//Process
Game.processEvents();
// Update
Game.simulationStep();
// Render
Game.render();
}
}
};
animator.start();
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...
I have a java app in which I use a thread. My thread runs every 20 seconds but, when it runs it kind of blocks the UI ... i. e. whenever the thread is running and the user clicks on button on anything on UI it doesnt respond sometimes.
Could anyone tell me a solution to this problem.
in java Swing, any change made to the state of the UI should be done in a single pre-existing thread called the EDT (event-dispatcher thread).
if that's not the case, you typically experience weird glitches / freezes. one of the most common symptom is that part of the UI becomes gray (except since java 1.6, where the ui is still painted like before, but unresponsive).
the good way to go is to use a dedicated method to queue your changes to the UI in the EDT :
SwingUtilities.invokeLater(Runnable toRunInEDT);
note that if you call invokeLater, the runnable is executed after all currently queued event have been dispatched. that means that the next line of code could be executed before the code in the runnable. there is a synchronous version as well (which should not be executed from the EDT):
SwingUtilities.invokeAndWait(Runnable toRunInEDT);
Some additional tips, on top of what edralzar said:
You can use the convenience method SwingUtilities.isEventDispatchThread() to check if code is in fact running on the event dispatch thread. And, like edralzar said, any code that creates GUI components, modifies the state of GUI components or reads the state of GUI components should run on the Event Dispatch Thread.
Another thing to consider, however, is that code running on the EDT should be able to execute rather quickly. So you cannot just solve things by running everything on the event dispatch thread. If you do the following, your GUI will be frozen for five seconds:
SwingUtilities.invokeLater(new Runnable(){
public void run(){
try{
Thread.currentThread().sleep(5000);
}catch(InterruptedException e){
//Ignored in this example
}
}
});
Why is it frozen? Because all GUI events and GUI updates are performed on the EDT, and if the EDT sleeps for 5000 miliseconds, no GUI updates can be performed during that time.
This article might be an interesting read.
Sounds to me like the thread you're referring to (that runs every 20 seconds) is also the thread that governs the UI.
The solution is to separate the two processes onto different threads.
I have a JFrame with a CardLayout set as its layout manager. This has two JPanel subclasses in it. One is a panel, WordsLoadingPanel, which displays the text "Loading words..." and has a JProgressBar. The other has to actually load the words. This takes a while (about 10-14 seconds for 100 words; it's a pretty selective algorithm), so I want to assure the user that the program is still working. I made the loading algorithm in the panel fire a property change with firePropertyChange(String, int, int), and the WordsLoadingPanel is catching the change just fine - I know this because I added a listener for this event to perform a println, and it works. However, when I change the println to actually changing the JProgressBar's value, it doesn't do anything. I know I'm changing the value right, because if I set the value before the algorithm starts, it works, and it works on the last iteration of the loop. I'm guessing this is because my algorithm is eating the computing power and won't let JProgressBar update.
So, my question is: How do I make my algorithm wait for Swing (would this be the AWT Dispatching Thread?) to finish updating the progress bar before continuing? I've tried:
Thread.yield in each iteration of the loop
Thread.sleep(1000L) in each iteration of the loop, in a try/catch
putting everything in the loop in a SwingUtilities.invokeLater(Runnable)
putting only the CPU-intensive algorithm in a SwingUtilities.invokeLater(Runnable)
EDIT: To further support my hypothesis of the CPU-eating algorithm (sounds like a children's story…), when I set the JProgressBar to indeterminate, it only starts moving after the algorithm finishes.
Does anyone have any suggestions?
Thanks!
To do expensive operations in background, consider using the SwingWorker class. The documentation has examples on how to use it to do tasks that interact with the user interface in a separate thread, including progress display in JProgressBars.
If you have trouble understanding how the class works, consider:
SwingWorker is a generic class that takes two parameters: T, and V
The doInBackground method returns T and is executed in a separate thread.
Since Swing may only be manipulated in the Event Dispatch Thread, you may not manipulate Swing in doInBackground.
The process method takes a List<V> as a parameter and is called asynchronously on the Event Dispatch Thread.
The publish method takes V... arguments and sends them for processing in the process method.
In conclusion:
T is the type of the result of the computation, if any.
V is the type of the data needed to manipulate the user interface.
Your algorithm should run entirely in doInBackground.
The user interface should be manipulated in the process method.
Your algorithm should use publish to send data to the process method.
OK, I've solved it. For anyone who may have a similar problem, my solution was to change the method which begun the algorithm from executing it synchonously to asynchronously (with new Thread(Runnable).start). So, my code is now
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Thread(new Runnable () {
public void run () {
window.keyboardTrainingPanel.initialize();
}
}).start();
}
});
I hope this can help someone! However, if there is a better way to do this, feel free to notify me.
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.