【问题标题】:How to define which property ListView should use to render如何定义 ListView 应该使用哪个属性来呈现
【发布时间】:2014-08-27 04:29:14
【问题描述】:

我有一个想要在 ListView 控件中显示的 java bean 对象列表。默认情况下,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() 试图获得可观察性,只有当它没有找到时它才会尝试访问标准 bean 属性。

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

【问题讨论】:

  • 为什么不重写 toString 方法?

标签: java listview javafx


【解决方案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】:

    绑定字符串属性

    此代码允许您选择在 ListView 中显示的 JavaFX 属性。我在 lambda 中使用了一个匿名类,以使正在发生的事情更加清晰。在这个例子中:

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

    说明

    使用这段代码,我们基本上是在制作一个自定义 ListCell。当它更新并且它显示的项目是null时,我们清除显示文本。否则,我们将文本设置为我们项目的标题属性。


    TL;DR :: 修改后的 James_D 的解决方案

    我以 James_D 的第二个示例为基础。我想将SimpleStringProperty 绑定为ListView 中显示的文本。 James_D 的解决方案效果很好,但是当我从 ListView 中的 ObservableList 中删除一个对象时没有更新,所以我对其进行了修改。我还认为有一个更干净的 lambda 示例会很好。

    【讨论】:

    • 感谢您的意见。但是我的问题是将属性名称作为字符串传递,而不是直接调用该方法。此外,对于我们可以使用简单 getter 的表,您的代码具有与 PropertyValueFactory 不同的行为。采用 Java 8 方法可能静态引用作为参数而不是字符串是可以接受的。
    猜你喜欢
    • 1970-01-01
    • 2017-07-22
    • 2012-05-28
    • 1970-01-01
    • 1970-01-01
    • 2012-07-27
    • 1970-01-01
    • 1970-01-01
    • 2018-11-27
    相关资源
    最近更新 更多