How to define which property ListView should use to render

java, javafx, listview

Solution

Use a cell factory.

If the property is immutable, it's pretty straightforward:

ListView<MyDataType> listView = new ListView<>();
listView.setCellFactory(new Callback<ListView<MyDataType>, ListCell<MyDataType>>() {
    @Override
    public ListCell<MyDataType> call(ListView<MyDataType> lv) {
        return new ListCell<MyDataType>() {
            @Override
            public void updateItem(MyDataType item, boolean empty) {
                super.updateItem(item, empty);
                if (item == null) {
                    setText(null);
                } else {
                    // assume MyDataType.getSomeProperty() returns a string
                    setText(item.getSomeProperty());
                }
            }
        };
    }
});

If the property can change its value and the list view needs to update dynamically in response to these changes, you need to bind the `textProperty` of the list cell:

listView.setCellFactory(new Callback<ListView<MyDataType>, ListCell<MyDataType>>() {
    @Override
    public ListCell<MyDataType> call(ListView<MyDataType> lv) {
        return new ListCell<MyDataType>() {
            @Override
            public void updateItem(MyDataType item, boolean empty) {
                super.updateItem(item, empty);
                textProperty().unbind();
                if (item == null) {
                    setText(null);
                } else {
                    // assumes MyDataType.someProperty() returns a StringProperty:
                    textProperty.bind(item.someProperty());
                }
            }
        };
    }
});

Problem

I have a java bean object list which I would like to display in ListView control. By default ListView uses toString method. How can I define which property to use for rendering in ListView? I want to achieve same functionality as in TableView can be achieved by PropertyValueFactory in this code: ``` @FXML private TableView<Person> mainTableView; //... TableColumn<Person,String> personColumn = new TableColumn<>("Name");List personColumn.setCellValueFactory(new PropertyValueFactory("name")); mainTableView.getColumns().add(personColumn); ``` Edit It looks like there is no easy(out of the box) solution. Based on code from James_D I created generic class to deal with the problem. It wraps PropertyValueFactory - note that PropertyValueFactory firstly looks for method [NAME]Property() trying to get observable, only when it is not found it tries to access standard bean properties. ``` public class PropertyValueFactoryWrapperCellFactory<T> implements Callback<ListView<T>, ListCell<T>> { private final PropertyValueFactory<T, String> pvf; public PropertyValueFactoryWrapperCellFactory(String propertyName) { super(); pvf = new PropertyValueFactory(propertyName); } @Override public ListCell<T> call(ListView<T> param) { return new ListCell<T>() { @Override public void updateItem(T item, boolean empty) { super.updateItem(item, empty); textProperty().unbind(); if (item == null) { return; } TableColumn.CellDataFeatures<T, String> cdf = new TableColumn.CellDataFeatures<>(null, null, item); textProperty().bind(pvf.call(cdf)); } }; } } ``` Usage: ``` @FXML private ListView<Person> mainListView; //... mainListView.setCellFactory(new PropertyValueFactoryWrapperCellFactory("name")); ```

Original source