具有自定义对象的JavaFX自定义单元工厂

我正在尝试使用基于自定义对象列表的自定义Cell构建自定义ListView.

自定义对象是名为Message的类名,它包含消息内容,收件人,时间戳和状态(读取,发送等)的几个字段.

看了这个问题:Customize ListView in JavaFX with FXML我成功了:

>创建了一个带有自定义单元格的ListView,其中单元格设计在FXML文件中定义;
>关联一个控制器,以便每个单元格数据可以用集合的当前项填充;

但是,我没有链接到两者:我似乎无法找到一种方法,以便ListView的当前项被发送到Cell Controller.

这是我的单元工厂代码和ListView项目填充:

final ObservableList observableList = FXCollections.observableArrayList();
observableList.setAll(myMessages); //assume myMessage is a ArrayList<Message>
conversation.setItems(observableList); //the listview
conversation.setCellFactory(new Callback<ListView<Message>, ListCell<Message>>() {
    @Override
    public ConversationCell<Message> call(ListView<Message> listView) {
        return new ConversationCell();
    }
});

而现在,ConversationCell类:

public final class ConversationCell<Message> extends ListCell<Message> { 

    @Override
    protected void updateItem(Message item, boolean empty) {
        super.updateItem(item, empty);
        ConversationCellController ccc = new ConversationCellController(null);
        setGraphic(ccc.getView());
    }
}

我无法显示ConversationCellController,但我可以说,这是(在其构造函数中)我加载设计单元格的FXML文件,然后我可以用给定的Message项填充值.

getView()方法返回包含现在填充和设计的单元格的根窗格.

正如我之前所说,设计工作,但我似乎无法将ListView项目与CellFactory链接,因为在方法中

protected void updateItem(Message item, boolean empty)

empty设置为true,item确实为null.

我能做些什么来完成这项工作?

最佳答案
覆盖updateItem(…)的所有自定义单元实现都需要处理该方法中单元格为空的情况.所以你可以做一个天真的解决方案

public final class ConversationCell<Message> extends ListCell<Message> { 

    @Override
    protected void updateItem(Message item, boolean empty) {
        super.updateItem(item, empty);
        if (empty) {
            setGraphic(null);
        } else {
            // did you mean to pass null here, or item??
            ConversationCellController ccc = new ConversationCellController(null);
            setGraphic(ccc.getView());
        }
    }
}

但是,从性能的角度来看,这不是一个好的解决方案.每次使用非空单元格调用updateItem(…)时都会加载FXML,这是一个相当昂贵的操作(可能涉及文件i / o,从jar文件中解压缩FXML文件,解析文件,批次反射,创建新的UI元素等).每当用户将列表视图滚动几个像素时,您不希望要求FX应用程序线程执行所有工作.相反,您的单元应缓存节点,并应在updateItem方法中更新它:

public final class ConversationCell<Message> extends ListCell<Message> { 

    private final ConversationCellController ccc = new ConversationCellController(null);
    private final Node view = ccc.getView();

    @Override
    protected void updateItem(Message item, boolean empty) {
        super.updateItem(item, empty);
        if (empty) {
            setGraphic(null);
        } else {
            ccc.setItem(item);
            setGraphic(view);
        }
    }
}

您应该在ConversationCellController中定义一个setItem(…)方法,该方法相应地更新视图(在标签上设置文本等).

转载注明原文:具有自定义对象的JavaFX自定义单元工厂 - 代码日志