Как определить, какое свойство ListView следует использовать для рендеринга

#java #listview #javafx

#java #listview #javafx

Вопрос:

У меня есть список объектов java bean, который я хотел бы отобразить в элементе управления ListView. По умолчанию ListView использует метод toString.

Как я могу определить, какое свойство использовать для рендеринга в ListView?

Я хочу добиться той же функциональности, что и в TableView, которая может быть достигнута с помощью PropertyValueFactory в этом коде:

 @FXML
private TableView<Person> mainTableView;
//...
TableColumn<Person,String> personColumn = new TableColumn<>("Name");List
personColumn.setCellValueFactory(new PropertyValueFactory("name"));
mainTableView.getColumns().add(personColumn);
  

Редактировать

Похоже, простого (готового) решения не существует. На основе кода из James_D я создал универсальный класс для решения проблемы. Оно обертывает PropertyValueFactory — обратите внимание, что PropertyValueFactory сначала ищет метод [NAME]Property(), пытаясь получить observable, и только когда он не найден, он пытается получить доступ к стандартным свойствам компонента.

 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));
            }
        };
    }

}
  

Использование:

 @FXML
private ListView<Person> mainListView;
//...
mainListView.setCellFactory(new PropertyValueFactoryWrapperCellFactory("name"));
  

Комментарии:

1. Почему бы вам не переопределить метод toString?

Ответ №1:

Используйте фабрику ячеек.

Если свойство является неизменяемым, это довольно просто:

 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());
                }
            }
        };
    }
});
  

Если свойство может изменять свое значение и представление списка должно динамически обновляться в ответ на эти изменения, вам необходимо привязать textProperty к ячейке списка:

 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());
                }
            }
        };
    }
});
  

Ответ №2:

Свойство привязки строки

Этот код позволяет вам выбрать, какое свойство JavaFX будет отображаться в ListView. Я использую анонимный класс внутри лямбда-выражения, чтобы внести некоторую ясность в происходящее. В этом примере:

  • Display — базовый объект, стоящий за ListView
  • titleProperty — отображаемое свойство JavaFX
 listView.setCellFactory( 
    listview -> { 
        return new ListCell<Display>() {
            @Override
            public void updateItem(Display item, boolean empty) {
                super.updateItem(item, empty);
                textProperty().unbind();
                if(item != null)
                    textProperty().bind(item.titleProperty());
                else
                    setText(null);
            }
        };
    }
);
  

Объяснение

С помощью этого кода мы в основном создаем пользовательскую ячейку списка. Когда оно обновляется и отображаемый в нем элемент становится null , мы очищаем отображаемый текст. В противном случае мы задаем текст таким, каким является свойство title нашего элемента.


TL; DR :: Модифицированное решение James_D

Я основал это на втором примере James_D. Я хотел привязать SimpleStringProperty к отображаемому тексту в ListView. Решение James_D отлично работало, но не обновлялось, когда я удалял объект из ObservableList в ListView, поэтому я изменил его. Я также подумал, что было бы неплохо иметь более чистый пример lambda.

Комментарии:

1. Спасибо за этот ввод. Однако моя проблема заключалась в передаче имени свойства в виде строки, а не в виде прямого вызова метода. Также ваш код ведет себя иначе, чем PropertyValueFactory для таблицы, где мы можем использовать простой метод получения. Используя подход Java 8, вероятно, статическая ссылка была бы приемлема в качестве параметра вместо строки.