Java FX Bindings
The graphic style of JavaFX is already quite nice. The architecture of JavaFX applied the lessons learned from the earlier Java framework AWT and Swing.
One of the other important innovations are the JavaFX bindings. They provide an elegant way to distribute dynamic information throughout a GUI application, and help separating business and GUI code.
The concept of bindings relies on the Observer Pattern, which says that a change producing instance can inform an interested party about a change that happenend.
The classic observer pattern informs all of its Observers, or Listeners immediately of and change. The JavaFX approach is to relax a bit and take the Lazy approach. Being lazy is good, because avoiding work that is (not yet) needed is a way to reduce work and in the end speed up an application.
tubmling dominos. source stkinfo.com
The idea is to only invalidate a value when a change happens, and only start the computation when some one
actually needs the result, for instance the GUI layer that needs to do a redraw.
Since Observables can be chained, changing one value may trigger a whole avalanche of computations.
In JavaFx, it is still an avalanche, but of invalidations, and no computations. The computation is only done
when some one needs the result.
JavaFX defines so called Properties in the javafx.beans
package and its sub-packages javafx.beans.properties
and javafx.beans.bindings
.
The Oracle tutorial by Scott Hommel sheds some light on the matter.
The Bindings and Properties packages provide several ways to create bindings, including expressions of various types, with specialized properties for int, long, and double as the most important specializations.
Binding APIs
Warning:
Quite often, and certainly when dealing with a GUI, you need to translate the values of a binding into
its String representation. In this case toString() does NOT cut it.
What you need is a StringBinding that is created
from the Binding you want to show as text. That is what public StringBinding asString() in the Binding framework is for.
Unbinding DoubleBinding dependencies
There are use cases where you have to unbind bindings. One such use case is the exercise FXTriangulate.
The DoubleBinding abstract class implements javafx.beans.binding.Binding, which states in its doc that the getDepencies()
method should not be used
in production code. We therefore will us a simpler approach.
Since the protected# bind(…)
and protected unbind()
methods both take a varargs argument, which is an array in disguise,
the only thing you can do is to remember all bound bindings and
when you have to unbind one, unbind all and then rebind the remaining.
This appears the most reliable method.
The binding and unbinding is necessary to make the binding listen to its dependencies.
Caching bindings
Creating bindings is powerful but can still lead to a performance bottleneck. If you create bindings willy-nilly, it might very well be that the same computation is done at several places and in a GUI screen redraw at almost the same time (or at least the reason) too.
To mitigate that problem, it can be wise to cache a binding once it’s created, and serve out the same binding on each subsequent call. A binding can have many Listeners, and it will dutifully inform all of them with either an invalidation call or change event. The Bindings themselves cache the value of the (last) computation and serve that out until it is 'discarded' on an invalidate call.
A naive approach to caching is to inspect a value for null and then instantiate one value when it is. In this case, because both the creation of the cache entries and the retrieval of the vale take place on the event thread, this naive approach works.
Warning:
The approach of inspecting a value for null and then instantiating a new object when null is NOT threadsafe. The approach works in this case, because it all happens on the event thread, on the same thread, so there will be no interfering threads.
Using SceneBuilder
When using SceneBuilder the idea is that you design the scene using SceneBuilder, which effectively is a what you see is what you get FXML editor. The JavaFx, more specifically the FXML part builds the graphical components or even the complete UI from such FXML files.
You can have multiple FXML files per application, much like you can have many scenes in a move or stage play.
There are various demos on Scenebuilder on youtube.
Creating or updating the java controller from the FXML file.
One of the most valuable tips from one of those videos is the fact that you can start with scenebuilder and define your graphical components and methods in SceneBuilder and hence in the fxml file and that then NetBeans IDE can generate or update the controller for you. Working in this way can help you avoid typing or (different) spelling errors.
Defining Widgets using FXML
You can use FXML to define whole scenes for your application, but also to make your own specialized components. You can then layout them as you want and import them into SceneBuilder, where they behave like any other widget already available. This allows you to extend the available choices, and make special widgets that can play nicely with something like a game or a planning application.
When you want to define your own component, you have to make a few changes to the FXML file and have the component class load the FXML by itself.
From the FXML file you can infer that the widget (in this case) is a specialized java.fx.Group. It can be any type that is a subclass of Parent (including Parent), if you want the widget to have sub-components.
Then in the Java file that is both controller and the subclass of the component you want to specialize, Group in the example.
In the example widget we have three dots connected with lines. The dots are draggable, while the lines stay connected. The lengths can be computed using Bindings and are thus automatically updated, and are shown next to the lines.
We will use such a widget in the next example.
Library settings hidden behind a cog-wheel.
Importing into scenebuilder is then done using the tiny cog next to the search text-field labeled Library. When you choose Jar/FXML Manager, you can add widget libraries like you would with maven or point at a library on you machine.
Reading
- Horstmann Core Java, Ed 11, Vol II, Ch 9, Bonus Chapter Volume I on JavaFX
More Links
- openjfx landing page and fxdocs
- JavaFX at Oracle
- An excellent site at Jakob Jenkov’s JavaFX Tutorials
- Dirk Lemmerman’s blog on JavaFx is an treasure trove on advanced JafaFX usage.
- Both Jakob and Dirk have a presence on youtube too.