← back to the blog


Observable Values

Posted in JavaFX

Imagine a view in JavaFx which displays some user data. This data is, at any time, likely going to change. Ever wondered how the view stays updated with respect to the data it is displaying? One way is to manually set the values in the corresponding node elements every time a change occurs. But this would dramatically add to a lot of extra work , not to mention unneeded headache for the developer. The other way is to make use of whats called an ‘Observable value’.

The Observer pattern

Before discussing ‘Observable values’ , lets understand the underlying principle.Observer pattern is a design pattern in which an observedvalue called the subject maintains a list of dependents. These dependents are called observers and they are notified of any change on the subject. Moreover, the subject never knows the identity of its observers in that the notion of an Observer is usually defined through an interface(or sometimes a super class) which ends up being implemented by several concrete classes.

ObservableValue

In JavaFx, ObservableValue is an interface that symbolises a subject. The classes that implement this interface essentially hold a value and a list of observers that are interested in the state of this value. If a change is made to the value thats being held, all the corresponding Observers will be notified of that change. In JavaFx, these observers are also referred to as ChangeListeners. Here is a class diagram that illustrates this relationship.

 

The ObservableValue interface itself defines three methods that the implementing classes implement: addListener() which is used to register an observer in the list of observers, removeListener() which does just the opposite i.e. removes it, and getValue() which retrieves the current value of the subject. It holds a list of ChangeListeners. Any time a change occurs on the observed value, the changed() method gets called.

We will look at a very simple example of an ObservableValue: SimpleStringProperty


public static void main(String[] args) throws InterruptedException {

    //Define a simple string property which is an Implementation of ObservableValue
    SimpleStringProperty simpleStringProperty=new SimpleStringProperty("OLD");
    System.out.println("Original Value is "+simpleStringProperty.getValue());

    //Add a listener to the above property
    simpleStringProperty.addListener(new ChangeListener() {

        //This method will be fired anytime the value of simpleStringProperty changes
        @Override
        public void changed(ObservableValue<? extends String> observableValue, String oldValue, String newValue) {
            System.out.println("Value changed from "+oldValue+" to "+newValue);
        }
    });

    //wait for 2 seconds
    Thread.sleep(2000);

    //change the value of the property
    simpleStringProperty.set("NEW");
}

In the above example,we create a SimpleStringProperty and add a ChangeListener to it, next we wait for 2 seconds(just for this demo’s sake) and then change the value of the simpleStringProperty. When this value gets changed, the ChangeListener is notified and its changed() is fired.

Another similar implementation of an ObservableValue is the SimpleIntegerProperty. In the below example we add some UI elements to demonstrate the same concept:


@Override
public void start(Stage stage) throws Exception {

    //instantiate a SimpleIntegerProperty
    final SimpleIntegerProperty simpleIntegerProperty=new SimpleIntegerProperty(99);

    //the string in textfield will always be updated, thanks to the observer that we register next.
    final TextField textField=new TextField(simpleIntegerProperty.getValue().toString());

    //we register an observer, which will be fired anytime the value of this property changes
    simpleIntegerProperty.addListener(new ChangeListener() {
        @Override
        public void changed(ObservableValue<? extends Number> observableValue, Number oldValue, Number newValue) {
            textField.setText(newValue.toString());
        }
    });

    //whenever we click the button, the value of the SimpleIntegerProperty gets changed
    Button button=new Button("Make it 100");
    button.setOnAction(new EventHandler() {
        @Override
        public void handle(ActionEvent actionEvent) {
            simpleIntegerProperty.set(100);
        }
    });

    //wrapping the whole thing up in a VBox
    VBox vBox=new VBox(40);
    vBox.setAlignment(Pos.CENTER);
    vBox.getChildren().addAll(textField,button);
    Scene scene=new Scene(vBox,150,100);
    stage.setScene(scene);
    stage.show();
}

The above example consists of a textfield and a button. First we setup a SimpleIntegerProperty that holds the value of 99, next we instantiate the textfield, giving it the current value of our integer property. Now, we add our ChangeListener which simply changes the value of the textfield to the newValue. Next, we instantiate a button and add an event handler to it. which gets fired when we click on it. In the Event Handler, we change the value of the SimpleIntegerProperty to 100, which in turn notifies all the listeners currently attached to this property. The listener,that we attached before now gets fired, and it changes the text in the textfield to the new value which is 100.

ObservableList

An ObservableList is similar to an ObservableValue. Much like an ObservableValue, an ObservableList notifies any listener which might be interested in tracking the state of this list. ObservableLists are widely used in JavaFx. In fact, the scene graph itself is made up of ObservableList for holding the children of a Parent node.

Now we will look at something we didn’t cover before: the ComboBox. This is the most common type of dropdown you will encounter in any UI driven application. Its simply a dropdown with a list of values to choose from.  Lets take a look at the code to present a simple ComboBox.


@Override
public void start(Stage stage) throws Exception {

    //create a list of item for the combo box to hold
    ObservableList monthList= FXCollections.observableArrayList();
    monthList.addAll("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec");

    //create a combo box for the above list
    ComboBox comboBox= new ComboBox<>(monthList);//parameter of the constructor,specfies the item list to hold
    comboBox.setLayoutX(100);
    comboBox.setLayoutY(30);

    //If nothing is selected this would show up on the combo box
    comboBox.setPromptText("Month");
    //show only 5 rows at a time
    comboBox.setVisibleRowCount(5);

    //put all the above in a simple Pane
    Pane pane =new Pane();
    pane.getChildren().addAll(comboBox);
    Scene scene=new Scene(pane,300,300);
    stage.setScene(scene);
    stage.show();
}

Setting up a simple ComboBox doesn’t take much work. The main thing here is the item list that the ComboBox holds. In the above example, we are simply using a list of Strings and passing it as an argument to the ComboBox’s constructor(you could otherwise use the setItems() ). The list of a ComboBox is of the ObservableList type.  So any time you make changes to this list elsewhere in your code, this ComboBox automatically gets updated. Neat!

JavaFx offers a variety of ObservableValue classes. We have seen a few of them in this tutorial. Often times an ObservableValue(or an ObservableList) holds the containing data as a generic. This allows a good amount of flexibility. To keep things concise, I will conclude this tutorial here. In the next tutorial we will cover Event Handling. Till then, see you.