javafx canvas 几秒钟后停止显示(我正在尝试百万个椭圆)

2024-01-04

我试图每秒在画布上动态显示一百万个椭圆形。我使用线程作为渲染线程,但我的问题是,几秒钟后,画布冻结并停止显示。我猜缓冲区已满,无法再显示,但是如何清除缓冲区呢?测试源码如下:

public class Main extends Application {

    public void start(Stage primaryStage) {
        primaryStage.setTitle("Drawing Operations Test");
        Group root = new Group();
        Canvas canvas = new Canvas(800, 800);
        GraphicsContext gc = canvas.getGraphicsContext2D();
        drawShapes(gc);
        root.getChildren().add(canvas);
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
        Task task2 = new Task<Void>()
        {
            public synchronized Void call() throws Exception {
                while (true) {
                    Thread.sleep(1000);
                    Canvas canvas = gc.getCanvas();
                    canvas.getGraphicsContext2D().clearRect(0, 0, canvas.getHeight(), canvas.getWidth());
                    drawShapes(canvas.getGraphicsContext2D());

                }
            }
        };
        Thread t = new Thread(task2);
        t.start();
    }

    private void drawShapes(GraphicsContext gc) {
        gc.setFill(Color.GREEN);
        gc.setStroke(Color.BLUE);
        gc.setLineWidth(1);
        double widthOval=1;
        double heightOval = 1;
        for (int i = 0; i < 500; ++i) {
            for (int j = 0; j < 500; ++j) {

                if (Math.random() < 0.5) {
                    gc.fillOval(i * widthOval, j * heightOval, widthOval, heightOval);
                }
                else {
                    gc.strokeOval(i * widthOval, j * heightOval, widthOval, heightOval);
                }
            }
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}

谁能帮我?

提前致谢,

Pierre


(可能)出了什么问题以及如何修复它

不要使用任务和单独的线程进行绘图。对场景图(包括画布)的修改必须在 JavaFX 应用程序线程上完成。相反,使用Timeline https://docs.oracle.com/javase/8/javafx/api/javafx/animation/Timeline.html(这将在 JavaFX 应用程序线程上隐式执行其关键帧代码)。如果你必须使用任务,那么至少使用平台.runLater https://docs.oracle.com/javase/8/javafx/api/javafx/application/Platform.html#runLater-java.lang.Runnable-将您的调用包围到修改活动场景图的 JavaFX API 中。

潜在的扩展问题

尝试在单帧中绘制每秒一百万个椭圆可能会很多。您可能希望运行一些基准测试,看看您的目标平台的可用数字是多少(尽管我下面的示例似乎在 2014 年 Macbook Pro 上执行得很好,没有出现性能问题)。

示例代码

这是带有时间线的更新示例,您可以尝试。它似乎对我来说工作得很好(Java 8u60,OS X 10.9.5) - 每秒渲染 250,000 个圆圈:

import javafx.animation.*;
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.canvas.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Duration;

public class LotsaCircles extends Application {
    private static final double SIZE = 500;

    public void start(Stage stage) {
        Canvas canvas = new Canvas(SIZE, SIZE);

        Timeline timeline = new Timeline(
                new KeyFrame(
                        Duration.seconds(0), 
                        event -> drawShapes(canvas.getGraphicsContext2D())
                ),
                new KeyFrame(Duration.seconds(1))
        );
        timeline.setCycleCount(Timeline.INDEFINITE);
        timeline.play();

        stage.setScene(new Scene(new Group(canvas)));
        stage.show();
    }

    private void drawShapes(GraphicsContext gc) {
        gc.clearRect(0, 0, SIZE, SIZE);
        gc.setFill(Color.GREEN);
        gc.setStroke(Color.BLUE);
        gc.setLineWidth(1);
        double widthOval = 1;
        double heightOval = 1;
        for (int i = 0; i < SIZE; ++i) {
            for (int j = 0; j < SIZE; ++j) {
                if (Math.random() < 0.5) {
                    gc.fillOval(i * widthOval, j * heightOval, widthOval, heightOval);
                }
                else {
                    gc.strokeOval(i * widthOval, j * heightOval, widthOval, heightOval);
                }
            }
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

javafx canvas 几秒钟后停止显示(我正在尝试百万个椭圆) 的相关文章

随机推荐