Canvas JavaFX画布绘制大量对象(<;250.000=>;500x500px)

Canvas JavaFX画布绘制大量对象(<;250.000=>;500x500px),canvas,drawing,javafx,2d,Canvas,Drawing,Javafx,2d,这是我向Stackoverflow提出的第一个问题,所以请温柔地回答我:) 我最近发现JavaFX是一种为Java应用程序设计GUI的新方法。目前,我正在从事一个项目,该项目需要在画布上绘制多达500x500(250.000)个对象,这些对象的大小可以从1x1px到20x20px(大小都相同)。 遗憾的是,演出不太好。绘制一个500x500矩形的字段大约需要10秒。 我制作了一个示例应用程序来演示这个问题 为什么表演这么差?由于绘图发生在UI线程中,因此UI将被阻止,直到绘图完成。 我有两个问题

这是我向Stackoverflow提出的第一个问题,所以请温柔地回答我:)

我最近发现JavaFX是一种为Java应用程序设计GUI的新方法。目前,我正在从事一个项目,该项目需要在
画布上绘制多达500x500(250.000)个对象,这些对象的大小可以从1x1px到20x20px(大小都相同)。
遗憾的是,演出不太好。绘制一个500x500矩形的字段大约需要10秒。
我制作了一个示例应用程序来演示这个问题

为什么表演这么差?由于绘图发生在UI线程中,因此UI将被阻止,直到绘图完成。 我有两个问题:

  • 画画要快
  • 在单独的线程中绘制缓冲区对象,并在画布上显示结果
  • 我在画布上绘制图像之前写入BuffereImage的实验失败了(画布一直是空的)

    感谢您花时间帮助研究此主题:)

    sample.fxml:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import java.lang.*?>
    <?import javafx.geometry.Insets?>
    <?import javafx.scene.control.*?>
    <?import javafx.scene.control.Button?>
    <?import javafx.scene.control.Label?>
    <?import javafx.scene.layout.*?>
    <?import javafx.scene.layout.GridPane?>
    
    <AnchorPane prefHeight="275.0" prefWidth="300.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="sample.Controller">
      <children>
        <ScrollPane fx:id="scrollPane" content="$null" prefHeight="237.0" prefWidth="300.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="38.0" />
        <Button layoutX="14.0" layoutY="14.0" mnemonicParsing="false" onAction="#draw" text="Draw" />
      </children>
    </AnchorPane>
    
    package sample;
    
    import javafx.event.ActionEvent;
    import javafx.fxml.FXML;
    import javafx.scene.canvas.Canvas;
    import javafx.scene.canvas.GraphicsContext;
    import javafx.scene.control.ScrollPane;
    import javafx.scene.paint.Color;
    
    import java.util.Random;
    
    public class Controller {
    
        @FXML
        private ScrollPane scrollPane;
    
        Canvas canvas;
        @FXML
        protected void draw(ActionEvent event) {
        canvas = new Canvas(500,500);
        scrollPane.setContent(canvas);
        GraphicsContext gc = canvas.getGraphicsContext2D();
            Random r = new Random();
    
            for(int i = 0; i<=500; i++) {
                for(int j = 0; j<=500; j++) {
                    if (r.nextBoolean()) {
                        gc.setFill(Color.BLACK);
                    } else {
                        gc.setFill(Color.BLUE);
                    }
                    gc.fillRect(i, j, i+1, j+1);
                }
            }
        }
    }
    
    package sample;
    
    import javafx.application.Application;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Parent;
    import javafx.scene.Scene;
    import javafx.scene.control.ScrollPane;
    import javafx.stage.Stage;
    
    public class Main extends Application {
    
        @Override
        public void start(Stage primaryStage) throws Exception{
            Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
            ScrollPane scrollPane = (ScrollPane) root.lookup("#scrollPane");
            primaryStage.setTitle("Hello World");
            primaryStage.setScene(new Scene(root, 300, 275));
            primaryStage.show();
        }
    
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    我怀疑根本原因可能与每次绘制调用都创建画布上下文有关。如果只填充画布一次并保留对其的引用,则可能会看到改进。另有说明:

    protected void draw(...) { canvas = new Canvas(...); }
    
    应移动到初始化

    public void start(...) { ... /* Other initialization. */ ... ; canvas = new Canvas(...); }
    
    其他一切都可以保持不变

    编辑1:我知道这个问题已经过时了,但这是谷歌排名很高的结果,应该有利于繁荣


    编辑2:在进一步的调查中,我认为这更多地与绘制调用的速度有关,而不是画布的实际获取。这个链接有更多的信息。总之,我会考虑强制硬件加速。您可以通过增量添加
    someCanvas.getGraphicsConfiguration()+.getBufferCapabilities()+.isPageFlipping()

    来检查您的呼叫是否处于活动状态。我想我可能知道问题出在哪里,请参阅
    gc.fillRect(i,j,i+1,j+1);
    大小随i&j的不同而变化。因此,假设您删除i&j,它的绘制速度相当快,每一个像素都位于我的末端。
    gc.fillRect(i,j,1,1);
    另一种方法是将画布分层,使用不同的画布作为背景,作为前景,通过堆叠多个画布更新object1,更新object2。您是如何解决这个问题的?