带有自定义对象的 JavaFX 自定义单元工厂 [英] JavaFX custom cell factory with custom Objects

查看:37
本文介绍了带有自定义对象的 JavaFX 自定义单元工厂的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用基于自定义 objects 列表的自定义 Cell 制作自定义 ListView.

I am trying to have a custom ListView made of custom Cell based on a list of custom objects.

自定义对象是名为 Message 的类名,其中包含一些消息字段内容收件人时间戳strong> 和 状态(已读、已发送等).

The custom object is class name called Message which contains a few fields for the message content, recipient, timestamp and status (read, sent etc.).

看了这个问题后:使用 FXML 在 JavaFX 中自定义 ListView 我已经成功:

After looking at this question : Customize ListView in JavaFX with FXML I have successfully :

  1. 使用自定义单元格创建了一个 ListView,其中单元格设计在 FXML 文件 中定义;
  2. 关联一个控制器,以便每个单元格数据都可以填充集合的当前项目;
  1. created a ListView with custom cells where the cell design is defined in a FXML file ;
  2. associated a controller so that each cell data can be filled with the current item of the collection ;

但是,我未能同时链接两者:我似乎无法找到将 ListView 的当前项目发送到 Cell Controller 的方法.

However, I failed to link both : I cannot seem to find a way so that the current item of the ListView is sent the Cell Controller.

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

Here is my code for the cell factory and the ListView filling of items:

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 类:

And now, the 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 文件的地方,然后我可以使用给定的 Message 项目填充值.

I cannot show the ConversationCellController but all I can say, this is where (in its constructor) I load the FXML file that designs the cell and then I can fill the values with the given Message item.

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

The getView() method returns the root pane that contains the now-filled-and-designed cell.

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

As I previously say, the designing work, but I cannot seem to link the ListView items with the CellFactory because in method

protected void updateItem(Message item, boolean empty)

protected void updateItem(Message item, boolean empty)

empty 设置为 true 并且 item 确实是 null.

empty is set to true and item is indeed null.

我该怎么做才能完成这项工作?

What can I do to make this work ?

推荐答案

所有覆盖 updateItem(...) 的自定义单元格实现都需要处理该方法中单元格为空的情况.所以你可以用

All custom cell implementations that override updateItem(...) need to deal with the case where the cell is empty in that method. So you could do a naïve fix of this with

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 方法中更新它:

However, this is not a good solution from the point of view of performance. You are loading the FXML every time updateItem(...) is called with a non-empty cell, and that'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 want to be asking the FX Application Thread to be doing all that work every time the user scrolls the list view by a few pixels. Instead, your cell should cache the node and should update it in the updateItem method:

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(...) 方法,相应地更新视图(设置标签上的文本等).

You should define a setItem(...) method in the ConversationCellController that updates the view (sets text on labels, etc etc) accordingly.

这篇关于带有自定义对象的 JavaFX 自定义单元工厂的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆