JavaFX 2.0 properties build upon the popular Java Beans pattern and enhance them with some useful and extremely powerful features. In this article, I will take a closer look at the usage of JavaFX properties. It is the first in a series of articles, which will explain JavaFX properties in detail.

JavaFX Beans

Let us assume we have a class Point with two double properties x and y. Both properties are JavaFX properties. The class would be defined as follows:

public class Point {
    public double getX() {...}
    public void setX(double x) {...}
    public DoubleProperty xProperty() {...}

    public double getY() {...}
    public void setY(double y) {...}
    public DoubleProperty yProperty() {...}
}

The getter and setter are no surprise. They are defined exactly as getters and setters are defined for JavaBeans. What is new are the other methods xProperty() and yProperty().  Both method names are created by concatenating the property name x respectively y and the String “Property”. The return type is an instance of the new class DoubleProperty, which encapsulates all of the new features. There are classes like this for the most common primitive types (double, float, int, long, and boolean), for Strings and for arbitrary Objects.

Class DoubleProperty

Let us take a closer look at DoubleProperty, the other properties are defined equivalent. The following list shows the property specific methods. DoubleProperty contains more methods, most of them related to the fluent API to create bindings. I will cover them in another article, for now we will just focus on the methods below.

public class DoubleProperty extends ... {
    public Object getBean() {...}
    public String getName() {...}

    public double get() {...}
    public void set(double v) {...} 

    public Double getValue() {...}
    public void setValue(Number value) {...}

    public void addListener(ChangeListener<? super Number> listener) {...}
    public void removeListener(ChangeListener<? super Number> listener) {...}

    public void addListener(InvalidationListener<? super Number> listener) {...}
    public void removeListener(InvalidationListener<? super Number> listener) {...}

    public void bind(ObservableValue<? extends Number> observable) {...}
    public void unbind() {...}
    public boolean isBound() {...}

    public void bindBidirectional(Property<Number> other) {...}
    public void unbindBidirectional(Property<Number> other) {...}
}

Getting the context

The first two methods getBean() and getName() return information about the context of the property. The method getBean() returns the object that contains the current property, the method getName() returns the name of it. For example, if you define a Point p1, the expression p1.xProperty().getBean() would return the containing Point p1 and p1.xProperty().getName() would return “x”. These two methods may look redundant, but there are situations, when you have to deal with instances of DoubleProperty directly without knowing the context, and in these situations getBean() and getName() come in very handy.

Getters and Setters

The next two methods get() and set() allow to get and set the value of a property. They are equivalent to the getter and setter defined in the containing object, i.e. p1.xProperty().get() is equivalent to p1.getX().

There is another pair of getter and setter (getValue() and setValue()), which use boxed types. These methods are mainly intended for code that needs to deal with all kinds of properties in a generic way. If you can, it is always recommended to use the primitive versions get() and set().

Attaching Listeners

The next four methods allow to attach and detach change-listeners and invalidation-listeners. The differences between change events and invalidation events can be very important. More about listeners is planned soon.

Bindings

A property can be bound to a target. This means, that the value of the property is synchronized with the target, i.e. it is guaranteed that the bound property and the target always contain the same value. Two kinds of bindings exist, unidirectional bindings and bidirectional bindings. A unidirectional binding works only in one direction, changes of the target are propagated to the property. A bidirectional binding works in both direction, changes are propagated from the target to the property, but also in the reverse direction from the property to the target.

A unidirectional binding imposes some limitations on the bound property. Once a property is bound, it is not possible to change its value in any other way, but by changes of the target. It is not possible to set the value with the setter, it would throw an Exception. And there can be only one unidirectional binding for a property at a time. The main advantage is, that you can bind a property to complex expression with unidirectional bindings. You can define these expressions with the Binding API. Every time one of the operands of such an expression changes, the property will be updated with the new result automatically. For example if you bind p1.xProperty() to the expression a + b, p1.getX() will always return the sum of a and b. If a or b change, p1.getX() will automatically return the new sum. With the method bind() you can define a unidirectional binding, unbind() removes the binding and isBound() checks if the property is bound at the moment.

A bidirectional binding on the other hand can only be established between properties of the same type. If one of the properties changes, the other property is updated, too. The usage is much more relaxed, you can still use the setter and it is even possible to define numerous bidirectional bindings for a single property. With bindBidirectional() a bidirectional binding can be defined and with unbindBidirectional() it can be removed.

Share

8 Comments on JavaFX Properties

  1. Steve says:

    “build upon the popular Java Beans pattern” … I guess by “popular” you don’t assume anyone seriously likes it but just that it is forced upon everyone?

    I really wonder: weren’t there any StrategyAdapterFactoryBuilders at Oracle left or why wasn’t the chance taken to make the API yet another bit more cumbersome?

    It does seem that not even the engineers building JavaFX for Java think anyone will seriously use it. Not surprised that the conference slides about JavaFX spend a dozen pages on “JavaFX with Java” but another 60+ on how it would be used from alternative languages.

  2. [...] my last article I gave an overview of the general functionality of JavaFX properties, this time I will explain how you can use JavaFX properties in your own [...]

  3. Rhys Parsons says:

    Nice to see a simple overview of the binding mechanisms. The API seems reasonable, but I think it’ll lead to a lot of boilerplate.

    It’ll be interesting to see what problems people have in practice.

  4. [...] Heinrichs, a member of the JavaFX team at Oracle, has blogged about JavaFX 2.0 properties. In another post, Michael has blogged about creating JavaFX 2.0 [...]

  5. Cedric sipa says:

    Hi
    i’m not sure this is a place to make my request but i hope someone will help me
    i’m tring for severals day now to convert this javafx1.3 code to javafx 2.0
    http://blogs.oracle.com/rakesh.....age_viewer
    can someone please help me to convert it?
    thanks

  6. Mike says:

    Sure, what exactly is your problem?

    AFAIK, there is a new version of DisplayShelf in the samples section of the SDK. Maybe it helps to look at the code that comes with it.

  7. LH Seadorf says:

    Mike
    How can I bind a property like firstName of a class Person, selected in a TableView, with the value of a TextField or another UI class ??
    Give an example, please.

  8. Mike says:

    Hi LH Seadorf,

    I apologize for the late reply. Your question came during my vacation and unfortunately I overlooked it after that.

    Just to make sure, I understand what you want correctly, I try to say it in my own words. You have a TableView and each row shows a different Person. The user should be able to select one row and the TextField should show the first name of that person. Is that, what you planned to do?

    I do not think, that you can do that with a single binding. If you bind the property firstName of the currently selected person to the TextField, then you need to make sure that you unbind the property once the user selects another person. I am not really an expert on the UI controls, but I think you can achieve what you intend with these lines (I wrote it from the top of my head, no guarantee that it works, just an idea of what could be done.):

    tableView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener () {
    @Override
    public void changed(ObservableValue< ? extends Person> observable, Person oldValue, Person newValue) {
    if (oldValue != null) {
    oldValue.firstNameProperty().unbindBidirectional(textField.textProperty());
    }
    if (newValue != null) {
    newValue.firstNameProperty().bindBidirectional(textField.textProperty());
    }
    }
    });

    The code attaches a change listener to the selectedItem property of a tableView. Every time the selected item is changed, the ChangeListener is executed. The listener unbinds the firstName of the previously selected person (oldValue) and then defines a binding between the new selected person (newValue) and the textField.