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

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

注意: 这里的一些代码不是我在实践中的做法,只是为了演示。我们假设资源始终存在并且不会抛出任何错误。

为了让图像显示在 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"))));
}

显然这效率不高,因为每个单元格都需要流式传输资源、制作对象等。因此,我认为下一个合乎逻辑的选择是将其移出并使其成为仅调用一次的静态对象。

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));
}

太棒了!仍然有效,我只需要阅读一次图像。图像也加载到单元格中,一切都很好。我仍在创建大量 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);
}

上面是它停止工作的地方,正如我预期的那样。在所有单元格中,现在只有最后一个单元格有图像,前面的单元格是空的。我不明白为什么。

我宁愿只实例化一个对象,特别是因为我的应用程序只需要将一个静态图像放入一个单元格中(它不会被更改)。

一个Node在场景图中只能出现一次。来自 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.

通常,ImageView 的几乎所有内存消耗都归结为 Image;因此,如果您在所有图像视图中共享相同的图像,您将变得非常高效。

此外,一般来说,不同的单元格可能有不同的大小,或者应用了不同的 CSS,因此在所有单元格之间共享一个 ImageView 根本行不通。 (如果它显示在多个单元格中,您希望 imgView.getParent() 到 return 是什么?)

您应该为您创建的每个 单元格 实例化一个 ImageView(而不是为 table 中的每个项目实例化一个)。然后您可以在所有 ImageView 之间共享图像。创建的单元格相对较少 - 它们根据需要重复使用以显示不同的项目。

所以我认为您的问题实际上来自于您将 ImageView 放入模型中(Data class),而不是将其保留在模型中查看(单元格)。

我会做类似的事情:

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

你没有在问题中说明你是如何使用图像的,但你会这样做:

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);
        }
    }
});

此解决方案只为每个单元格创建一个 Image 和一个 ImageView,而不是为 [=] 中的每个值创建一个 ImageView 的工作版本47=]的项目列表。