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

JavaFX custom cell factory with custom Objects

我正在尝试根据自定义 objects.

列表由自定义 Cell 制作自定义 ListView

自定义对象是 class 名为 Message 的名称,其中包含消息的一些字段 contentrecipient时间戳状态(已读、已发送等)。

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

  1. 使用 自定义单元格 创建了一个 ListView,其中单元格设计在 FXML 文件 中定义;
  2. 关联了一个控制器,这样每个单元格数据都可以用集合的当前项填充;

但是,我未能link两者:我似乎无法找到一种方法将 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 class :

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 文件的地方(在其构造函数中),然后我可以用给定的消息项填充值。

getView() 方法 returns 根窗格 包含现在已填充和设计的单元格。

正如我之前所说,设计工作,但我似乎无法 link 带有 CellFactory 的 ListView 项目,因为在方法

protected void updateItem(Message item, boolean empty)

empty 设置为 true 并且项目确实是 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());
        }
    }
}

但是,从性能的角度来看,这不是一个好的解决方案。每次使用 non-empty 单元格调用 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(...) 方法来相应地更新视图(在标签上设置文本等)。