Binding a List of Strings to a JavaFx ListView

Adding and modifying a List of Strings in a JavaFx ListView is a relatively easy task, although may not be completely intuitive at first glance.  In order to have changes to a List automatically reflected in a ListView you will need to make use of the ListProperty class, however setting items in the property is not as easy as calling the add() or addAll() methods.  This is because the underlying ObservableList class that the Property is using does not support the add() or addAll() methods.  Instead, you will need to first wrap your List in an ObservableList, and then pass that ObservableList to the ListProperty instance.

Below is an small sample application which illustrates this point.  There are two ArrayLists which contain Strings of data.  One contains the currency codes of some Asian currencies, and the other contains the currency codes of European currencies.  The list should initially be loaded with the Asian currencies, and when the user clicks on the Button, the handleButtonAction() method is invoked, which will cause the European currency list to be rendered in the ListView.

First, the FXML layout for the UI.

<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="201.0" prefWidth="131.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.40" fx:controller="com.lynden.testjavafxlistview.AppController">
<children>
<Button fx:id="button" layoutX="14.0" layoutY="160.0" onAction="#handleButtonAction" prefHeight="26.0" prefWidth="100.0" text="Click Me!" />
<ListView fx:id="myListView" layoutX="14.0" layoutY="21.0" prefHeight="109.0" prefWidth="100.0" />
</children>
</AnchorPane>

view raw
Scene.xml
hosted with ❤ by GitHub

Next, the controller class for the application

package com.lynden.testjavafxlistview;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
public class AppController implements Initializable {
@FXML
private Button button;
@FXML
private Label label;
@FXML
private ListView myListView;
protected List<String> asianCurrencyList = new ArrayList<>();
protected List<String> europeanCurrencyList = new ArrayList<>();
protected ListProperty<String> listProperty = new SimpleListProperty<>();
@FXML
private void handleButtonAction(ActionEvent event) {
listProperty.set(FXCollections.observableArrayList(europeanCurrencyList));
}
@Override
public void initialize(URL url, ResourceBundle rb) {
asianCurrencyList.add("CNH");
asianCurrencyList.add("JPY");
asianCurrencyList.add("HKD");
asianCurrencyList.add("KRW");
asianCurrencyList.add("SGD");
europeanCurrencyList.add("EUR");
europeanCurrencyList.add("GBP");
europeanCurrencyList.add("NOK");
europeanCurrencyList.add("SEK");
europeanCurrencyList.add("CHF");
europeanCurrencyList.add("HUF");
myListView.itemsProperty().bind(listProperty);
//This does not work, you can not directly add to a ListProperty
//listProperty.addAll( asianCurrencyList );
listProperty.set(FXCollections.observableArrayList(asianCurrencyList));
}
}

view raw
AppController.java
hosted with ❤ by GitHub

The two lists are populated within the initialize() method of the controller.  As you can see it is not possible simply to call the addAll() method on the ListProperty, as it will result in an “OperationNotSupportedException”.  Instead, at line 57, the FXCollections class is used to wrap the ArrayList in an ObservableArrayList instance, which is then passed into the ListProperty.

Finally, in the handleButtonAction() method, the europeanCurrencyList is wrapped in ObservableList, and passed to the ListProperty.  Since the ListProperty and the ListView are bound together (at line 53), the ListView is automatically updated with the European currency values.

Below are screenshots of the sample app both before and after the button has been clicked.

Asian Currencies

Asian currency list before clicking button.

Screen Shot 2015-09-21 at 4.48.36 PM

European currency list after clicking button.

 

 

 

 

 

 

 

 

twitter: @RobTerpilowski
LinkedIn Profile: Rob Terpilowski

 

 

7 thoughts on “Binding a List of Strings to a JavaFx ListView

  1. Pingback: Java desktop links of the week, September 28 « Jonathan Giles

  2. What you’re doing is creating a new ObervableList every time the action is performed.

    What you need to do instead is instantiate SimpleListProperty with a list implementation, this way support is provided by the backing list:

    protected SimpleListProperty listProperty
    = new SimpleListProperty(FXCollections.observableArrayList());

    Now in your handleButtonAction you can simply addAll

    listProperty.addAll(europeanCurrencyList);

  3. Just a follow up the pattern should be to expose the API methods of the backing observable collection to your controller methods instead of calling on SimpleListProperty:

    private final ObservableList observableList
    = FXCollections.observableArrayList();
    private final SimpleListProperty listProperty
    = new SimpleListProperty(observableList);

    now you can addAll on observableList.

Leave a Reply