Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Properties and bindings

In JavaFX almost every value of a control (the text of a field, the tick of a check box, whether a button is enabled) is stored in a property. A property is a wrapper around a value that tells all its subscribers when the value changes. Thanks to this, one value can be bound to another, and JavaFX keeps it up to date by itself.

Control properties

Each property has a method ending in Property:

ValueOrdinary methodProperty
Field textgetText()textProperty()
Check box tickisSelected()selectedProperty()
Button disabledisDisable()disableProperty()
Text lengthgetLength()lengthProperty()

A change listener

You can attach a listener to a property: a lambda with three parameters, the property itself, the old value and the new one:

// src/main/java/com/example/notes/App.java — part of start()
importantBox.selectedProperty().addListener((observable, oldValue, newValue) ->
        System.out.println("Important: " + oldValue + " -> " + newValue));

Tick the check box and the terminal shows Important: false -> true.

Binding

bind ties a property to another value for good: when the source changes, the bound property changes too. Let's show a character counter under the note text:

// src/main/java/com/example/notes/App.java — part of start()
Label charsLabel = new Label();
charsLabel.textProperty().bind(textArea.lengthProperty().asString("Characters: %d"));

asString turns the number into a string with a pattern, like String.format. The label updates with every typed letter. Add it to the grid: form.add(charsLabel, 1, 4).

A button without if

Bindings can compute conditions. The "Add" button will be disabled while the title is empty:

// src/main/java/com/example/notes/App.java — part of start()
addButton.disableProperty().bind(titleField.textProperty().isEmpty());

isEmpty() returns not a boolean but a BooleanBinding, which is recalculated on every change of the text. There are others too: isNotEmpty(), isNull(), greaterThan(), and(), not().

Your own property

You can create a property for your own data as well. Let's count the added notes:

// src/main/java/com/example/notes/App.java — part of the class
private final IntegerProperty count = new SimpleIntegerProperty(0);
 
// in start():
Label countLabel = new Label();
countLabel.textProperty().bind(count.asString("Notes: %d"));
 
// in addNote():
count.set(count.get() + 1);

Put countLabel into the left panel instead of the "No notes yet" label: new VBox(countLabel). The handler changes only the number, and the label text updates by itself.

Other types have SimpleStringProperty, SimpleBooleanProperty, SimpleDoubleProperty and SimpleObjectProperty.

Trying it out

Run the application. On the left is "Notes: 0", and the "Add" button is grey. Type a title and the button becomes enabled. Click it twice with different titles and the left side shows "Notes: 2". Type "Hello" in the text and "Characters: 5" appears under the check box.

Common mistake

A bound property cannot be set by hand. If you call charsLabel.setText("...") after charsLabel.textProperty().bind(...), the program crashes with java.lang.RuntimeException: Label.text : A bound value cannot be set. Remove the binding with unbind() first or change the source instead. For a two-way link, for example between a field and a model property, use bindBidirectional.

Thanks for reading!

Donate to the site — we work hard for you.