Navigation using a ListView in JavaFX

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

The Schema Editor app I’ve been working on has two main panes in its UI: the menu on the left and the editor and the center.

In the previous posts we were able to create a reactive menu and make the name of the schema editable.

The Application after it started

React when a Schema is selected in the ListView

We want the editor view to reflect the correct schema when selecting the schema from the ListView.

This is not something you can do in FXML. However, you can get a property that tracks the currently selected item: listView.getSelectionModel().selectedItemProperty()

public class AppController {
    @FXML private ListView<Schema> schemaListView;
    @FXML private TextArea schemaEditor;

    private final ObjectProperty<Schema> selectedSchemaProperty 
        = new SimpleObjectProperty<>();

    @FXML
    public void initialize() throws IOException {
        ObservableList<Schema> schemas = FXCollections.observableArrayList();
        schemaListView.setEditable(true);
        schemaListView.setCellFactory(param -> new SchemaListCell());
        schemaListView.setItems(schemas);

        selectedSchemaProperty.bind(schemaListView.getSelectionModel().selectedItemProperty());
        selectedSchemaProperty.addListener((observable, oldValue, newValue) -> {
            schemaEditor.setText(newValue.getRaw());
        });

        // Load data
        InitialDataLoader dataLoader = new InitialDataLoader();
        schemas.addAll(dataLoader.load());
    }
}

Don’t forget to add fx:id="schemaEditor" to the TextArea in the .fxml file.

Textarea updates based on the selected item in the ListView

Textarea updates based on the selected item in the ListView.

Using EasyBind

I worked in the past with RxJava which also have a type called Observable (its sematic varies from the JavaFX Observable though). One of the thing that I enjoy was possibility to use function such as .map() to transform an observable.

While the Bindings util class offers some tools to do transformation of observables, I am not found of its ergonomics. I prefer to use the EasyBind library instead:

// When the selected schema changes
selectedSchemaProperty.bind(schemaListView.getSelectionModel().selectedItemProperty());
schemaEditor.textProperty().bind(
    EasyBind.monadic(selectedSchemaProperty)
        .selectProperty(Schema::rawProperty)
);

I could skip using the selectedSchemaProperty variable altogether:

// When the selected schema changes
schemaEditor.textProperty().bind(
    EasyBind.monadic(schemaListView.selectionModelProperty())
        .flatMap(SelectionModel::selectedItemProperty)
        .selectProperty(Schema::rawProperty)
);

Don’t forget to add the esybind dependency to your pom.xml and module-info.java files.

I’m a big fan of monads as they allow to make my code linear, hence easier to read.