简体   繁体   English

JavaFX需要多个ImageView节点而不是一个引用?

[英]JavaFX requires multiple ImageView nodes rather than a reference to one?

Note: Some of the code in here is not how I would do it in practice, but is just for demonstration. 注意: 这里的一些代码不是我在实践中的方式,而只是为了演示。 We'll assume resources are always present and no errors are thrown. 我们假设资源始终存在,并且不会引发任何错误。

In a quest to get images to display in a TableView, I got a prototype working from a testing POJO in a test MVC application like so: 为了使图像显示在TableView中,我从测试MVC应用程序中的测试POJO得到了一个原型,如下所示:

public Data(String name) {
    this.nameProperty = new SimpleStringProperty(name);
    this.imageProperty = new SimpleObjectProperty<ImageView>(new ImageView(new Image(Data.class.getResourceAsStream("img.png"))));
}

Obviously this is not efficient because every single cell will need to stream the resource, make an object...etc. 显然,这效率不高,因为每个单元都需要流式传输资源,创建对象等。 Therefore I figured the next logical option was to move this out and make it a static object that is invoked only once. 因此,我认为下一个逻辑选项是将其移出并使其成为仅被调用一次的静态对象。

private static final Image img = new Image(Data.class.getResourceAsStream("img.png"));

public Data(String name) {
    this.nameProperty = new SimpleStringProperty(name);
    this.imageProperty = new SimpleObjectProperty<ImageView>(new ImageView(img));
}

Great! 大! Still works and I only had to read the image once. 仍然有效,我只需要阅读一次图像。 The image loads into the cells as well and all is great. 图像也加载到单元中,一切都很好。 I am still creating a ton of ImageView objects, so I try to move it outside as well. 我仍在创建大量ImageView对象,因此我也尝试将其移到外面。

private static final Image img = new Image(Data.class.getResourceAsStream("img.png"));

private static final ImageView imgView = new ImageView(img); // Assume loaded 2nd and properly always

public Data(String name) {
    this.nameProperty = new SimpleStringProperty(name);
    this.imageProperty = new SimpleObjectProperty<ImageView>(imgView);
}

The above is where it stops working as I expected it to. 以上是它停止工作的地方,正如我期望的那样。 Out of all the cells, only the last cell has the image now and the preceding ones are empty . 在所有单元格中, 只有最后一个单元格现在具有图像,而前面的单元格为空 I don't understand why. 我不明白为什么。

  • Is an ImageView node supposed to be referenced only once? 一个ImageView节点应该只被引用一次吗? Why can't I have the node referenced in multiple cells? 为什么不能在多个单元格中引用该节点?

  • Is there some optimization under the hood that only renders a node once? 是否在引擎优化下仅渲染一个节点一次?

  • Is there a way for me to do this with only making one ImageView object? 我有办法只制作一个ImageView对象吗?

  • Would using the SimpleObjectProperty have any effect on why I need multiple instantiations of an ImageView for the same Image? 使用SimpleObjectProperty是否会对为什么我需要为同一张Image的多个ImageView实例化产生任何影响?

I'd rather only instantiate one object, especially since my application only needs to just put a single static image into a cell (it will not be changed). 我宁愿只实例化一个对象,尤其是因为我的应用程序只需要将一个静态图像放入一个单元格(它不会被更改)。

A Node can only appear once in the scene graph. 一个Node在场景图中只能出现一次。 From the Javadocs : Javadocs

A node may occur at most once anywhere in the scene graph. 一个节点最多可以在场景图中的任何位置出现一次。 Specifically, a node must appear no more than once in all of the following: as the root node of a Scene, the children ObservableList of a Parent, or as the clip of a Node. 具体来说,一个节点在以下所有所有条件中最多只能出现一次:作为场景的根节点,父级的子级ObservableList或节点的剪辑。

Usually, almost all the memory consumption of an ImageView is down to the Image ; 通常, ImageView几乎所有内存消耗都ImageView Image so if you share the same image among all the image views, you will be making things pretty efficient. 因此,如果您在所有图像视图中共享相同的图像,则将使事情变得非常有效。

Moreover, in general, different cells may be different sizes, or have different CSS applied to them, so sharing a single ImageView among all the cells simply wouldn't work. 而且,通常,不同的单元可能具有不同的大小,或者将不同的CSS应用于它们,因此在所有单元之间共享单个ImageView根本行不通。 (And what would you expect imgView.getParent() to return if it were displayed in multiple cells?) (如果imgView.getParent()显示在多个单元格中,您会期望返回什么?)

You should instantiate one ImageView for each cell you create (not one for each item in the table). 您应该为创建的每个单元实例化一个ImageView (而不是为表中的每个项目实例化)。 You can then share the image among all the ImageView s. 然后,您可以在所有ImageView共享图像。 Relatively few cells are created - they are reused as needed to display different items. 创建的单元格相对较少-根据需要重新使用它们以显示不同的项目。

So where I think your problem is actually coming from is that you're putting the ImageView into the model (the Data class), instead of keeping it in the view (the cell). 因此,我认为您的问题实际上出在哪里,是您将ImageView放入模型( Data类),而不是将其保留在视图(单元格)中。

I would do something like: 我会做类似的事情:

public class Data {
    private final StringProperty name ;
    public Data(String name) {
        this.name = new SimpleStringProperty(name);
    }
    // getName/setName/nameProperty methods....
}

You haven't shown in the question how you are using the image, but you would do something like this: 您尚未在问题中显示出如何使用图像,但是您会执行以下操作:

final Image img = new Image(Data.class.getResourceAsStream("img.png"));

// ...

TableView<Data> table = new TableView<>();
TableColumn<Data, String> column = new TableColumn<>("Name");
column.setCellValueFactory(cellData -> cellData.getValue().nameProperty());

column.setCellFactory(col -> new TableCell<Data, String>() {
    private final ImageView imageView = new ImageView(img);

    @Override
    public void updateItem(String item, boolean empty) {
        super.updateItem(item, empty);
        if (empty) {
            setText(null);
            setGraphic(null);
        } else {
            setText(item);
            setGraphic(imageView);
        }
    }
});

This solution creates just one Image , and just one ImageView for each cell, instead of the working version you have that creates an ImageView for every value in the table's items list. 此解决方案仅为每个单元格创建一个Image ,并且仅创建一个ImageView ,而不是为表的项目列表中的每个值创建一个ImageView的工作版本。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM