GridView 仅在图像可见时创建图像

tct*_*fox 4 java gridview javafx controlsfx

嘿那里

所以我有以下问题。我有大约 1500 张扑克牌图像。我想将它们显示在“图库”中,您可以在其中滚动浏览它们。我能够使用 ImageCell 对象创建 GridView,并且还能够向其中添加图像。现在我的问题是,如果我一次添加所有图像,逻辑上Java会因为堆错误而崩溃。我的列表中有图像网址(本地文件)。我怎样才能实现它只加载 15 张图像。如果我滚动它,它会加载接下来的 15 个并卸载旧的。所以它只会加载实际可见图像的图像,而不是全部 1500 个图像。我该怎么做?我完全没有主意了。需要 Platform.runLater() 因为 ControlsFX 存在某种问题

这是我的代码:

    public void initialize() {

    GridView<Image> gridView = new GridView<>();
    gridView.setCellFactory(gridView1 -> new ImageGridCell(true));
    Image image = new Image("C:\\Users\\nijog\\Downloads\\cardpictures\\01DE001.png");

    gridView.setCellWidth(340);
    gridView.setCellHeight(512);

    //Platform.runLater(()-> {
    //    for (int i = 0; i < 5000; i++){
    //        gridView.getItems().add(image);
    //    }
    //});

    Platform.runLater(() -> gridView.getItems().addAll(createImageListFromCardFiles()));

    borderPane.setCenter(gridView);

}

protected List<Image> createImageListFromCardFiles(){

    List<Image> imageViewList = new ArrayList<>();
    App.getCardService().getCardArray().stream()
            //.filter(Card::isCollectible)
            .sorted(Comparator.comparingInt(Card::getCost))
            .sorted(Comparator.comparing(Card::isChampion).reversed())
            .skip(0)
            //.limit(100)
            .forEach(card -> {
                try {
                    String url = String.format(App.pictureFolderPath +"%s.png", card.getCardCode());
                    imageViewList.add(new Image(url));
                } catch (Exception e) {
                    System.out.println("Picture file not found [CardCode = " + card.getCardCode() + "]");
                    App.logger.writeLog(Logger.Operation.EXCEPTION, "Picture file not found [CardCode = " + card.getCardCode() + "]");
                }
            });
    return imageViewList;
}
Run Code Online (Sandbox Code Playgroud)

Jam*_*s_D 5

您可能不需要使用您所描述的策略。您在大小为 340x512(即 174,080 像素)的单元格中显示图像。图像存储为每个像素 4 字节,因此每张图像为 696,320 字节;其中 1500 个将消耗约 1GB。您只需要确保以显示的尺寸加载图像(而不是其原始尺寸):

// imageViewList.add(new Image(url));
imageViewList.add(new Image(url, 340, 512, true, true, true));
Run Code Online (Sandbox Code Playgroud)

如果您稍后需要全尺寸的图像(例如,如果您希望用户从网格视图中选择图像并将其显示在更大的窗格中),则只需从 URL 重新加载它即可。

如果您确实需要实施您所描述的策略,请GridView立即提供支持。只需保留 URL 列表(而不是 s)Image,并根据需要使用自定义GridCell加载图像。这将消耗显着更少的内存,但代价是更多的 I/O(加载图像)和 CPU(解析图像格式)。

GridView为图像 url创建项目,存储为字符串。

然后你可以做类似的事情:

GridView<String> gridView = new GridView<>();
gridView.getItems().addAll(getAllImageURLs());

gridView.setCellFactory(gv -> new GridCell<>() {
    private final ImageView imageView = new ImageView();

    {
        imageView.fitWidthProperty().bind(widthProperty());
        imageView.fitHeightProperty().bind(heightProperty());
        imageView.setPreserveRatio(true);
    }

    @Override
    protected void updateItem(String url, boolean empty) {
        super.updateItem(url, empty);
        if (empty || url == null) {
            setGraphic(null);
        } else {
            double w = getGridView().getCellWidth();
            double h = getGridView().getCellHeight();
            imageView.setImage(new Image(url, w, h, true, true, true));
            setGraphic(imageView);
        }
    }
});


protected List<String> getAllImageURLs(){

    return App.getCardService().getCardArray().stream()
            // isn't the first sort redundant here?
            .sorted(Comparator.comparingInt(Card::getCost))
            .sorted(Comparator.comparing(Card::isChampion).reversed())
            .map(card -> String.format(App.pictureFolderPath +"%s.png", card.getCardCode()))
            .collect(Collectors.toList());
}
Run Code Online (Sandbox Code Playgroud)