Introduction to Properties and Databinding in JavaFX

This post is part of the 100 Days of JavaFX Series.

In the previous article, we made a Schema model class a simple Java Bean. We did not exactly follow all the rules for a Java bean but what mattered was to have private attributes with getters and setters. To make the model work nicely with JavaFX we need to make it a JavaFX Bean.

From Java Bean to JavaFX Bean

How does JavaFX Bean differ from your traditional Java Bean? As for Java Beans, the concept of JavaFX Bean is a convention:

  • Its attributes use “Property” types instead of basic types (IntegerProperty instead of int or Integer)
  • Its property attributes are final — the value inside the property changes, not the property instance itself
  • Getters will read inside the property: age.getValue();
  • Setters will write inside the property: age.setValue();
  • Exposes its property: public IntegerProperty ageProperty() { }

The Property Interface

Its basic building blocks are:

  • (Interface) ObservableValue — an entity that wraps content and allows to observe the content for invalidations
  • (Interface) WritableValue — an entity that wraps a value that can be read and set

A Property is a a wrapped writeable value whose changes can be observed.

Property class hierarchy

A simply view of the hierarchy of classes and interfaces available to define an Integer Property. In bold are the ones you are the most likely to be using.

Code Examples

A property is a container for a value that can change over time.

IntegerPropery a = new SimpleIntegerProperty(1);
a.setValue(2);
a.setValue(3);

We change the value inside of a, but always points to the same instance of IntegerPropery. Property fields can usually be final because they won’t need to change.

final IntegerPropery a = new SimpleIntegerProperty(1);
a.setValue(2); // Will work

The main benefit of this approach is that we can more easily track value changes.

IntegerProperty a = new SimpleIntegerProperty(1);
a.addListener((observable, oldValue, newValue) -> {
  System.out.printf("Value changed from %d to %d %n", oldValue.intValue(), newValue.intValue());
});
a.setValue(2);
a.setValue(3);

// Will print:
// Value changed from 1 to 2 
// Value changed from 2 to 3

A property has the concept of binding, that is having the value of a property following another.

IntegerProperty a = new SimpleIntegerProperty(1);

IntegerProperty b = new SimpleIntegerProperty(0);
b.bind(a);
b.addListener((observable, oldValue, newValue) -> {
  System.out.printf("Value changed from %d to %d %n", oldValue.intValue(), newValue.intValue());
});

a.setValue(2);
a.setValue(3);

// Will print:
// Value changed from 1 to 2 
// Value changed from 2 to 3

In this example, we listen on b, but are performing the changes on a. Because b is bound to a, changes from a are propagated to b.

Binding and Property Are Two Different Things

JavaFX have a different interface for Property and Binding:

Unlike a property, you can’t set an arbitrary value to a binding. Bindings only react to what it is bound to by performing a predetermined transformation.

In the next example, the multiple method allows us to define a binding to our property and transform it by multiplying the value by a number.

IntegerProperty a = new SimpleIntegerProperty(1);
IntegerBinding b = a.multiply(2);

b.addListener((observable, oldValue, newValue) -> {
  System.out.printf("Value changed from %d to %d %n", oldValue.intValue(), newValue.intValue());
});

a.setValue(2);
a.setValue(3);

// Will print:
// Value changed from 2 to 4 
// Value changed from 4 to 6

Properties and binding are key elements that will allow to make our UI more dynamic.