当前位置: 首页 > 知识库问答 >
问题:

只画应该在屏幕上的节点?

呼延曜灿
2023-03-14

我在JavaFX中使用场景图(不是画布)进行模拟,但在屏幕上只画我需要的东西时遇到了问题。

该模拟中有1000万个节点,但用户只需要在屏幕上同时看到这些节点的一小部分(最多160000个节点)。我关心的所有节点都是400x400<code>ImageViews

每个节点都是包含大约40000个节点的(节点块)的成员,因此每次需要显示4个或更少的节点块。为了显示这些“节点块”,它们被添加到静态窗格中,该窗格位于根节点中,这是一个

所以我从第一个父母到最后一个孩子的图表如下所示:

根节点<代码>组 \显示<代码>窗格 \(多个)节点块<代码>组 \

由于显示窗格根据用户输入不断移动(平移和重新缩放),并且有如此多的节点,因此应用程序无法以我想要的速度运行。JavaFX无法同时跟踪1000万个节点,这是有道理的,所以我的解决方案是从显示窗格中删除所有“节点块”;将它们保存在哈希映射中,直到我需要绘制它们为止。

每个“节点块”都将其 LayoutXLayoutY设置为在显示窗格中均匀分布,如下所示:

在本例中,我需要抓取并显示“节点块”7、8、12和13,因为这是用户看到的。

以下是手动添加“节点块”0的屏幕截图。绿黄色是放置“节点块”1、5和6的位置。

我的问题是:由于“节点块”在需要之前不会添加到显示窗格中,因此我无法参考它们相对于用户看到的显示窗格不断变化的部分的布局边界,因此我不知道哪些“节点块”需要显示。

有什么简单的方法可以解决这个问题吗?还是我走错了路?(或者两者兼而有之)谢谢。

共有2个答案

壤驷涛
2023-03-14

我最终为每个“节点块”创建了一个矩形,将不透明度设置为零,然后检查了与用户看到的显示窗格部分的冲突。当发生与矩形的冲突时,相应的“节点块”将添加到显示窗格中。

郎宏浚
2023-03-14

注意:这不是您的确切问题的答案。

我不知道为什么要为每张图片创建ImageView。相反,我会为每个nodeChunk绘制一个图像(160000个图像),并为这个nodeChunk创建一个ImageView。

从功能上来说,我看不出这两种方法有什么不同(你可以让我知道你为什么想用每种imageview)。但是从性能上看,这种方法非常快速和平滑。

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;

    import java.awt.*;
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import java.security.SecureRandom;
    import java.util.HashMap;
    import java.util.Map;

    /**
     * Combining 4,000,000 images
     */
    public class ImageLoadingDemo extends Application {

        SecureRandom rnd = new SecureRandom();
        // I created 5 images of dimension 1 x 1  each with new color
        String[] images = {"1.png", "2.png", "3.png", "4.png", "5.png"};
        Map<Integer, BufferedImage> buffImages = new HashMap<>();
        Map<Integer, Image> fxImages = new HashMap<>();

        @Override
        public void start(Stage primaryStage) throws IOException {
            ScrollPane root = new ScrollPane();
            root.setPannable(true);
            Scene scene = new Scene(root, 800, 800);
            primaryStage.setScene(scene);
            primaryStage.show();

            root.setContent(approach1());  // Fast & smooth rendering

            // Your approach of creating ImageViews
            // root.setContent(approach2());  // Very very very very very slow rendering
        }

        private Node approach1(){
            // Creating 5 x 5 nodeChunk grid
            GridPane grid = new GridPane();
            for (int i = 0; i < 5; i++) {
                for (int j = 0; j < 5; j++) {
                    ImageView nodeChunk = new ImageView(SwingFXUtils.toFXImage(createChunk(), null));
                    grid.add(nodeChunk, i, j);
                }
            }
            return grid;
        }

        private BufferedImage createChunk() {
            // Combining 160000 1px images into a single image of 400 x 400
            BufferedImage chunck = new BufferedImage(400, 400, BufferedImage.TYPE_INT_ARGB);
            Graphics2D paint;
            paint = chunck.createGraphics();
            paint.setPaint(Color.WHITE);
            paint.fillRect(0, 0, chunck.getWidth(), chunck.getHeight());
            paint.setBackground(Color.WHITE);
            for (int i = 0; i < 400; i++) {
                for (int j = 0; j < 400; j++) {
                    int index = rnd.nextInt(5); // Picking a random image
                    BufferedImage buffImage = buffImages.get(index);
                    if (buffImage == null) {
                        Image image = new Image(ImageLoadingDemo.class.getResourceAsStream(images[index]));
                        buffImages.put(index, SwingFXUtils.fromFXImage(image, null));
                    }
                    paint.drawImage(buffImage, i, j, null);
                }
            }
            return chunck;
        }

        private Node approach2(){
            GridPane grid = new GridPane();
            for (int i = 0; i < 5; i++) {
                for (int j = 0; j < 5; j++) {
                    grid.add(createGroup(), i, j);
                }
            }
            return grid;
        }
        private Group createGroup() {
            GridPane grid = new GridPane();
            for (int i = 0; i < 400; i++) {
                for (int j = 0; j < 400; j++) {
                    int index = rnd.nextInt(5);
                    Image fxImage = fxImages.get(index);
                    if (fxImage == null) {
                        fxImage = new Image(ImageLoadingDemo.class.getResourceAsStream(images[index]));
                        fxImages.put(index, fxImage);
                    }
                    grid.add(new ImageView(fxImage), i, j);
                }
            }
            return new Group(grid);
        }



        public static void main(String[] args) {
            Application.launch(args);
        }
    }
 类似资料:
  • 我在Android上实现了一个用于绘图的画布,但是绘图视图充满了屏幕。我想调整这个屏幕的大小。我该怎么办? 一旦我将MyView设置为在oncreate方法中使用setContentView显示。 mainactivity.java 这是在画布上作画的部分。但是,如前所述,我想调整一下我可以画画的范围。我不希望整个屏幕都是一个绘图视图。MyView.java

  • 那么当屏幕被锁定时,是否有任何方法显示特定的XAML页面。目前我正在使用toast通知来完成此操作。但是toast通知的问题是我对UI没有太多的控制。

  • 我使用HTML2Canvas渲染两个反应组件,问题是文档的输出只呈现屏幕上可见的内容,所以如果组件的内容很短,我可以看到pdf中的所有内容,但是,如果内容很长,我需要滚动到页面的顶部,使其工作,或者我需要将我的导航缩放到50%,然后单击print 我的代码中是否有错误:

  • 我正在使用libgdx,我有一个平铺的地图,我想把精灵画在上面。然而,精灵被绘制到实际的窗口上,所以当我移动相机时,精灵保持在原来的位置?我想让精灵在地图上移动。 这就是我当前渲染对象的方式 它总是在屏幕的中间,但是我想能够像移动相机一样移动它们(例如,W,A,S,D),并用方向键移动我的播放器。然后,如果我想把相机锁定在播放器上,但从另一方面来说,它是免费的。 我是libgdx的新手,所以请容忍

  • 问题内容: 我想构建一个锁屏更换应用程序。有什么方法可以创建一个侦听器/服务,该监听器/服务将在用户唤醒/解锁屏幕时启动我的应用程序? 问题答案: 请参阅mylockforandroid的源代码, 您将需要使用DeviceAdminReceiver来禁用默认的Android 屏幕锁。 当用户解锁屏幕将and 注册为时启动活动: 将此代码添加到manifast.xml中,将ScreenReceive

  • 我试图移动这个图像: 在我的PyGame屏幕上,从右到左再向后,但是随着图像的移动,每隔一秒左右我就会有一点屏幕撕裂,就像这样: 我使用的代码是类似于此的循环: 到目前为止,我已经尝试了以下方法来解决这个问题: 在创建屏幕时使用,,标志,这没有效果,我也调整了更新为(因为使用?)时建议使用此选项) 在GPU和CPU之间拆分内存(我在raspberry pi 2上运行此功能)我尝试过为这两个处理器提