Update your Scene in JavaFX
February 9, 2014 12 Comments
Usually it is very simple to update your scene in JavaFX. For example if you want to update the X and Y position of your nodes, you can often simply do some stuff like:
node.setLayoutX(100d); node.setLayoutY(150d);
But this isn’t a good way of doing it. In JavaFX you have to be sure you are in the JavaFX application thread. But how can you know this?
Platform.isApplicationFxThread();
But what if you’re not in that thread?
Platform.runLater(Runnable r);
So each time you would like to update your scene manually, you should check if you’re or not in the FX application thread. So let’s make a really simple helper class:
/** * @author Thierry Wasylczenko */ public class PlatformHelper { public static void run(Runnable treatment) { if(treatment == null) throw new IllegalArgumentException("The treatment to perform can not be null"); if(Platform.isFxApplicationThread()) treatment.run(); else Platform.runLater(treatment); } }
The method run does the check for you. Finally you can use a lambda expression to execute that code:
final Node node = ... ; PlatformHelper.run(() -> { node.setLayoutX(100d); node.setLayoutY(150d); });
That’s it.
Pingback: JavaFX links of the week, February 10 // JavaFX News, Demos and Insight // FX Experience
Pingback: Java desktop links of the week, February 10 « Jonathan Giles
How much different (better?) is this from just always assuming you’re not on the JavaFX thread and always use runLater?
I would say to have things done correctly 🙂 I don’t really know if it is much better than always use runLater. I could imagine that it is more efficient by avoiding the JavaFX platform to “queue” that event. I think that if you redraw one thing at a time it should be okay, but if you have a lot of updates to make, I think it would avoid useless treatments for the platform. Maybe Jonathan is much more able to answer to your question 🙂
I have an identical method for Swing, but have been debating (with myself) the value of it for many years.
Well, in FX8 you also have SwingUtilities#invokeLater for embedding Swing content in JFX.
Yes. Well, I’m talking pure swing:
static public void invokeLater(Runnable runnable)
{
// if this is the AWT thread, just run it
if (EventQueue.isDispatchThread() ) runnable.run();
else
{
// this is not the AWT thread, hand it over
javax.swing.SwingUtilities.invokeLater( runnable );
}
}
Interesting to see how the same things pop up 🙂
If it pops up in Swing and JFX, I think it is a nice idea 😀
My opinion is that you only want to put things into the runLater queue if you need to. If you are already on the JavaFX application thread then you should not queue the runnable up, and instead perform it immediately. It is generally the advice in UI toolkits to not put too much on the queue as it can result in pulses that are too slow to keep up the expected frame rate.
Interesting arguments. OTOH the method now has a delaying effect on the current pulse, so that could be a poteto potato thingy. Plus it has a duality; changes may be immediate, or they may not. Anyhow, not too relevant I guess.
Is there an addon to a JavaFX application that allows you to find code that does not ‘behave properly’ with respect to Application Thread?
If there is one, I don’t know it sorry.