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.
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.
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.