You can bind a target object to a source object. A change in the source object will be automatically reflected in the target object. JavaFX introduces a new concept called property binding that enables a target object to be bound to a source object. If the value in the source object changes, the target object is also changed automatically. The target object is called a binding object or a binding property and the source object is called a bindable object or observable object. As discussed in the preceding listing, the circle is not centered after the window is resized. In order to display the circle centered as the window resizes, the x- and y-coordinates of the circle center need to be reset to the center of the pane. This can be done by binding the centerX with pane’s width/2 and centerY with pane’s height/2, as shown in the program below.
The Circle class has the centerX property for representing the x-coordinate of the circle center. This property like many properties in JavaFX classes can be used both as target and source in a property binding. A target listens to the changes in the source and automatically updates itself once a change is made in the source. A target binds with a source using the bind method as follows:
target.bind(source);
The bind method is defined in the javafx.beans.property.Property interface. A binding property is an instance of javafx.beans.property.Property. A source object is an instance of the javafx.beans.value.ObservableValue interface. An ObservableValue is an entity that wraps a value and allows to observe the value for changes.
JavaFX defines binding properties for primitive types and strings. For a double/float/long/int/boolean value, its binding property type is DoubleProperty/FloatProperty/LongProperty/IntegerProperty/BooleanProperty. For a string, its binding property type is StringProperty. These properties are also subtypes of ObservableValue. So they can also be used as source objects for binding properties.
By convention, each binding property (e.g., centerX) in a JavaFX class (e.g., Circle) has a getter (e.g., getCenterX()) and setter (e.g., setCenterX(double)) method for returning and setting the property’s value. It also has a getter method for returning the property itself. The naming convention for this method is the property name followed by the word Property. For example, the property getter method for centerX is centerXProperty(). We call the getCenterX() method as the value getter method, the setCenterX(double) method as the value setter method, and centerXProperty() as the property getter method. Note that getCenterX() returns a double value and centerXProperty() returns an object of the DoubleProperty type.
Figure below (a) shows the convention for defining a binding property in a class and Figure below (b) shows a concrete example in which centerX is a binding property of the type DoubleProperty.
The program in Listing 14.5 is the same as in Listing 14.4 except that it binds circle’s centerX and centerY properties to half of pane’s width and height (lines 16–17). Note that circle.centerXProperty() returns centerX and pane.widthProperty() returns width. Both centerX and width are binding properties of the DoubleProperty type. The numeric binding property classes such as DoubleProperty and IntegerProperty contain the add, subtract, multiply, and divide methods for adding, subtracting, multiplying, and dividing a value in a binding property and returning a new observable property. So, pane.widthProperty().divide(2) returns a new observable property that represents half of the pane’s width. The statement
circle.centerXProperty().bind(pane.widthProperty().divide(2));
is same as
centerX.bind(width.divide(2));
Since centerX is bound to width.divide(2), when pane’s width is changed, centerX automatically updates itself to match pane’s width / 2.
The program below gives another example that demonstrates bindings.
The program creates an instance of DoubleProperty using
SimpleDoubleProperty(1) (line 7). Note that DoubleProperty, FloatProperty, LongProperty, IntegerProperty, and BooleanProperty are abstract classes. Their concrete subclasses SimpleDoubleProperty, SimpleFloatProperty, SimpleLongProperty, SimpleIntegerProperty, and SimpleBooleanProperty are used to create instances of these properties. These classes are very much like wrapper classes Double, Float, Long, Integer, and Boolean with additional features for binding to a source object.
The program binds d1 with d2 (line 9). Now the values in d1 and d2 are the same. After setting d2 to 70.2 (line 11), d1 also becomes 70.2 (line 12).
The binding demonstrated in this example is known as unidirectional binding. Occasionally, it is useful to synchronize two properties so that a change in one property is reflected in another object, and vice versa. This is called a bidirectional binding. If the target and source are both binding properties and observable properties, they can be bound bidirectionally using the bindBidirectional method.