首页 文章

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

提问于
浏览
10

我正在尝试根据自定义 objects 列表自定义 ListView 自定义 Cell .

自定义对象是名为 Message 的类名,其中包含消息 contentrecipienttimestampstatus (读取,发送等)的几个字段 .

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

  • 使用 custom cells 创建了一个ListView,其中单元格设计在_730657中定义;

  • 关联 controller ,以便每个单元格数据可以用集合的当前项填充;

但是,我无法链接两者:我似乎无法找到一种方法,以便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() 方法返回包含现在填充和设计的单元格的 root pane .

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

protected void updateItem(消息项,布尔值为空)

empty 设置为 true ,项目确实是 null .

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

1 回答

  • 9

    覆盖 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,并且每次用户将列表视图滚动几个像素时,'s a pretty expensive operation (potentially involving file i/o, unzipping the FXML file from a jar file, parsing the file, lots of reflection, creating new UI elements, etc). You don' t都要求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(...) 方法,以相应地更新视图(在标签上设置文本等) .

相关问题