如何指定JavaFX ListView在使用自定义对象时应显示的属性?

时间:2017-06-16 20:59:34

标签: listview user-interface javafx

我在FXML文件中定义了一个ListView,它将保存MyCustomData对象。我可以弄清楚如何告诉它显示MyCustomData的哪个属性的唯一方法是将以下代码添加到我的控制器:

myList.setCellFactory(new Callback<ListView<MyCustomData>, ListCell<MyCustomData>>() {
    @Override
    public ListCell<MyCustomData> call(ListView<MyCustomData> param) {
        return new ListCell<MyCustomData>() {
            @Override
            protected void updateItem(MyCustomData item, boolean empty) {
                super.updateItem(item, empty);
                if(item != null) {
                    setText(item.getMyProperty());
                }
            }
        };
    }
});

用FXML中的单行代码替换所有这些混乱的代码肯定会很好,它指定了应该显示的属性。这可能吗?

1 个答案:

答案 0 :(得分:1)

首先请注意,您的单元格实现存在错误。您必须处理updateItem(...)方法中的所有可能性。在您的实现中,如果单元格当前显示一个项目,然后重新用作空单元格(例如,如果项目被删除),则单元格将不会清除其文本。

如果将Callback实现为lambda表达式而不是匿名内部类,则可以显着减少代码量:

myList.setCellFactory(lv -> new ListCell<MyCustomData>() {
    @Override
    protected void updateItem(MyCustomData item, boolean empty) {
        super.updateItem(item, empty);
        setText(item == null ? null : item.getMyProperty() );
    }
});

如果您正在做很多这样的事情,并希望进一步减少代码量,那么创建一个通用的可重用单元工厂实现并不困难:

public class ListViewPropertyCellFactory<T> 
    implements Callback<ListView<T>, ListCell<T>> {

    private final Function<T, String> property ;

    public ListViewPropertyCellFactory(Function<T, String> property) {
        this.property = property ;
    }

    @Override
    public ListCell<T> call(ListView<T> listView) {
        return new ListCell<T>() {
            @Override
            protected void updateItem(T item, boolean empty) {
                super.updateItem(item, boolean);
                setText(item == null ? null : property.apply(item));
            }
        };
    }
}

可以与

一起使用
myList.setCellFactory(new ListViewPropertyCellFactory<>(MyCustomData::getMyProperty));

如果您更喜欢使用功能更强的样式来创建实现Callback的类,那么您也可以这样做

public class ListViewPropertyCellFactory {

    public static <T> Callback<ListView<T>, ListCell<T>> of(Function<T, String> property) {
        return lv -> new ListCell<T>() {
            @Override
            protected void updateItem(T item, boolean empty) {
                super.updateItem(item, boolean) ;
                setText(item == null ? null : property.apply(item));
            }
        };
    }
}

myList.setCellFactory(ListViewPropertyCellFactory.of(MyCustomData::getMyProperty));