Binding Java Objects in JavaFX Script

Bindings are one of the key features of the JavaFX language, because they simplify one´s life tremendously. By reducing the amount of boilerplate code, which is usually needed to keep the objects in an application in-sync, the developer can concentrate on the really important things. (You know, like a cool looking UI.) 😉

Unfortunately Java objects do not provide this capabilities for their fields. That means the boilerplate code has to be written manually. This article will show a solution to bind properties of Java objects.

Overview

Let´s assume, we have a Java class Rectangle with the four properties x, y, width, and height. We want to show the rectangle on the screen using JavaFX script and update its position and size as the properties of the Java object change.

The code of the class Rectangle would be something like this:

 1 public class MyRectangle {
 2     private int x, y;
 3     private int width, height;
 4
 5     public int getX() { return x; }
 6     public void setX(int x) { this.x = x; }
 7     public int getY() { return y; }
 8     public void setY(int y) { this.y = y; }
 9     public int getWidth() { return width; }
10     public void setWidth(int width) { this.width = width; }
11     public int getHeight() { return height; }
12     public void setHeight(int height) { this.height = height; }
13
14     // ... more functionality here
15 }

Code Sample 1: First draft of MyRectangle

What we want the JavaFX script to look like, is this:

 1 import javafx.stage.Stage;
 2 import javafx.scene.Scene;
 3 import javafx.scene.shape.Rectangle;
 4
 5 Stage {
 6     scene: Scene {
 7     // ... more attributes here
 8         content: Rectangle {
 9             x: bind r.x
10             y: bind r.y
11             width: bind r.width
12             height: bind r.height
13         }
14     }
15 }

Code Sample 2: JavaFX program binding the rectangle

This looks simple enough and the only question remaining is: what is “r”? To allow the script to bind to the fields of the Java object, we need to introduce an adapter between the two, which provides a more JavaFX-like interface of the Java class and which will take care of the synchronization. A simplified class-diagram of the three objects is shown in Figure 1:

Class Diagram

Class Diagram

The basis interface of the adapter can be defined as follows:

 1 public class RectangleAdapter {
 2     public-read var x: Integer;
 3     public-read var y: Integer;
 4     public-read var width: Integer;
 5     public-read var height: Integer;
 6
 7     public-init var javaRectangle: MyRectangle;
 8 }

Code Sample 3: First draft of the adapter RectangleAdapter

Only thing left to do is to add the following line to the script in Listing 3. This will create a new instance of RectangleAdapter and its adaptee Rectangle.

var r = RectangleAdapter { javaRectangle: new MyRectangle }
Looks like we are about halfway through. We defined an adapter and connected it to the JavaFX class. Now let's take a look at the second part: connecting the adapter with the Java object.

Synchronizing with the Java object

Synchronizing the adapter whenever the state of the Java object changes requires some more work. In general there are two possibilities to implement this functionality. The first solution is to make the adapter an observer (or "listener" to speak more Java-like) of the Java object. This is usually the preferred approach, unfortunately it is not always possible. For example, if you are dealing with existing classes, which you cannot change, this approach would be problematic. The second solution, which does not require any changes to the Java class, is to request the current state repeatedly.
Synchronizing using the observer-pattern
There are numerous ways to implement the observer-pattern. Since this article is not so much about implementing Java programs, I will use the simplest approach by extending Observable. This is a utility-class, which provides all of the functionality required by the observer-pattern. All we need to do is add the code to initiate the notification of our observers. The class Observable requires two method-calls for that: setChanged() to signal the object has changed and notifyObservers() to start the notification-process. In our code example, I added a small private method startNotification() to bundle both calls and updated the setters. Code sample 4 shows the new version of the class Rectangle.
 1 import java.util.Observable;
 2
 3 public class MyRectangle extends Observable {
 4     private int x, y;
 5     private int width, height;
 6
 7     public int getX() { return x; }
 8     public void setX(int x) {
 9         this.x = x;
10         startNotification();
11     }
12
13     public int getY() { return y; }
14     public void setY(int y) {
15         this.y = y;
16         startNotification();
17     }
18
19     public int getWidth() { return width; }
20     public void setWidth(int width) {
21         this.width = width;
22         startNotification();
23     }
24
25     public int getHeight() { return height; }
26     public void setHeight(int height) {
27         this.height = height;
28         startNotification();
29     }
30     private void startNotification() {
31         setChanged();
32         notifyObservers();
33     }
34
35     // ... more functionality here
36 }

Code Sample 4: MyRectangle implementing Observable

To finish this solution, we need our adapter to extend the interface Observer. That requires to implement its method update(), and to register the adapter. The registration is done by calling addObserver() in the onReplace-trigger of the attribute javaRectangle.

The method update() comes with two parameters, which are helpful, if we want to observe more than one object or if we are dealing with different events. But in our code example, we can ignore them. Only thing left to do is pull the new values from javaRectangle and update the attributes of the adapter.

But wait! You have to be careful here. While our Java code can run on any thread, JavaFX Script is picky here. We need to make sure, that the update is done on the right thread, otherwise the bindings and subsequent actions might fail.

JavaFX Script provides a mechanism for this. The method FX.deferAction() takes a simple function as a parameter and makes sure, that it is executed on the right thread. The complete adapter is shown in code sample 5.

 1 import java.lang.Object;
 2 import java.util.Observable;
 3 import java.util.Observer;
 4
 5 public class RectangleAdapter extends Observer {
 6     public-read var x: Integer;
 7     public-read var y: Integer;
 8     public-read var width: Integer;
 9     public-read var height: Integer;
10
11     public-init var javaRectangle: MyRectangle
12         on replace { javaRectangle.addObserver(this); }
13
14     override function update(observable: Observable, arg: Object) {
15         FX.deferAction(
16             function(): Void {
17                 x = javaRectangle.getX();
18                 y = javaRectangle.getY();
19                 height = javaRectangle.getHeight();
20                 width = javaRectangle.getWidth();
21             }
22         );
23     }
24 }

Code Sample 5: RectangleAdapter implementing Observer

Synchronizing by pulling the state

The second solution does not require any change to the Java class. Let's assume, we do not want to bind to an object of our own Rectangle, but to an instance of java.awt.Rectangle. This class does not provide any mechanisms to observe state-changes. Instead we have to pull the current state on a regular base to notice changes.

The JavaFX class PauseTransition provides exactly the needed functionality. It comes with two main attributes to setup the behavior. The parameter action defines the task, which needs to be executed, and the parameter duration defines the gap between two consecutive calls.

Defining the right value for the duration is probably the toughest part. The best choice depends on the context. If the value is too low, precious CPU cycles are wasted, if the value is too high, the update might come too late. In our example, the duration is set to 10 ms, which ensures smooth animations.

The adapter for the second solution is shown in code sample 6. Note, that we do not have deal with threading in this solution, because the action of the ActionTransition is already executed on the right thread.

 1 import java.awt.Rectangle;
 2 import javafx.animation.Timeline;
 3 import javafx.animation.transition.PauseTransition;
 4
 5 public class RectangleAdapter {
 6     public-read var x: Integer;
 7     public-read var y: Integer;
 8     public-read var width: Integer;
 9     public-read var height: Integer;
10
11     var action: PauseTransition;
12     public-init var javaRectangle: Rectangle
13         on replace {
14             action = PauseTransition {
15                 duration: 10ms
16                 action: function(): Void {
17                     x = javaRectangle.x;
18                     y = javaRectangle.y;
19                     height = javaRectangle.height;
20                     width = javaRectangle.width;
21                 }
22                 repeatCount: Timeline.INDEFINITE;
23             }
24             action.play();
25         }
26
27     public function stop() {
28         action.stop();
29     }
30 }

Code Sample 6: RectangleAdapter pulling the status

Summary

This article presented two solutions to implement a simple binding of a Java object. The first solution is always preferable, because it uses CPU cycles only when an update took place, while the second solution burns cycles even when nothing happens. The second solution is a fall back in cases, where the observer pattern cannot be implemented.

11 responses to “Binding Java Objects in JavaFX Script”

  1. chris oliver Avatar

    Both approaches are uncool imo. POJO’s don’t have the underlying infrastructure to support binding unfortunately. The best you can do is neither of the above, but rather to automatically support Java’s limited change notification infrastructure: i.e bean properties. This was implemented in F3, and could be implemented with the JavaFX compiler. Of course, the limitations of POJO’s and bean properties are one of the very reasons JavaFX script was created in the first place…

  2. Michael Heinrichs Avatar
    Michael Heinrichs

    Yes, some automated support would be a much better option (although I believe there are more important issues right now). After my vacation I will check if a feature request exists.
    Until then you have to write the boilerplate-code yourself, even if it is "uncool". 🙂

  3. Carl Avatar
    Carl

    Could we use byte code engineering on the Java side to put the boilerplate code in beans?

    Or some factory to wrap a pojos like the presentation pattern.

    Should JavaFX support annotation to indicate properties to synchronize? Just throwing ideas.

    -Carl

  4. Eric Avatar
    Eric

    Can either of these approaches be modified to support bi-directional binding, i.e., "with inverse"?

  5. Eric Avatar
    Eric

    To answer my own question: Yes, binding with inverse appears to work well with either method, and the adapter can use ‘on replace’ to implement changes. Be careful though as third party changes to the model will result in potentially redundant updates.

  6. Markus Avatar
    Markus

    Hi,
    it seems this example doesn´t work since JavaFX Version 1.1 released.
    The First Solution only work when you leave the statement

    15 FX.deferAction(
    16 function(): Void {
    17 x = javaRectangle.getX();
    18 y = javaRectangle.getY();
    19 height = javaRectangle.getHeight();
    20 width = javaRectangle.getWidth();
    21 }
    22 );

    out and just sign your properties at this position:

    override function update(observable: Observable, arg: Object) {

    x = javaRectangle.getX();
    y = javaRectangle.getY();
    height = javaRectangle.getHeight();
    width = javaRectangle.getWidth();
    }

  7. Peter Avatar
    Peter

    hi,

    is it possible to create the rectangle object in a java class?
    for example having a rectangle factory building an instance with every click?
    need this because i want to parse a xml file with Sax and for every tag creating a rectangle in the stage.

    regards
    peter

  8. Peter Avatar
    Peter

    hi,

    is it possible to create the rectangle object in a java class?
    for example having a rectangle factory building an instance with every click?
    need this because i want to parse a xml file with Sax and for every tag creating a rectangle in the stage.

    regards
    peter

  9. Peter Avatar
    Peter

    btw: i want to control the objects with java classes and then the changed should be visible in the stage?

  10. Vali Avatar

    Hi,

    I`m trying to create a graph like in this example: http://www.clarin.eu/vlw/blark-hierarchy.php using Java FX. I`m new with Java FX, and I hope that you can help me with this, maybe a useful link or something

    Thanks, good job

  11. Sel Avatar
    Sel

    Hi Experts,

    its been an hour and I cant still get how to successfully import java.util.observable class on JavaFX mobile. Can someone give a guide or information how can I successfully run it together with my "JavaFX Runned in mobile Emulator project"?

    Does the source code above is from a standard/web/browser runned application?

    Sincerely Thanks in advance,
    Sel