绘制多个画布后 JavaFX 应用程序无响应

时间:2021-05-06 14:15:20

标签: java javafx canvas

我有一个应用程序,我想在其中显示一个 FlowPane,其中包含绘制到画布中的 PDF 页面缩略图。我正在使用 PDFBoxFXGraphics2D 来呈现页面。 我当前的实现创建了许多画布作为页面数,将它们添加到 FlowPane,然后旋转多个或异步任务以将页面内容绘制到画布中。

我不确定异步绘图是否是推荐的方式,但我的想法是不使用 JavaFX 线程进行 PDF 解析以避免冻结应用程序。 现在,我的问题是这样的,我可以从日志中看到所有渲染任务都已完成并且文档已关闭。 UI 显示了一些呈现的页面,但它保持无响应约 10 秒。之后应用程序恢复,所有页面都被呈现并且一切正常。

我尝试分析,我认为这是相关部分: profiler 但是我对引擎盖下发生的事情的了解有限,我无法弄清楚我做错了什么。您对我的方法/代码有什么问题以及如何改进有任何想法或提示吗?理想情况下,我希望在填充页面缩略图时应用程序快速响应。

我在 Linux 上使用一台相当不错的机器,但我也在 Windows 上进行了测试并得到了相同的行为。我还尝试将 FlowPane 替换为 HBoxVBox,但仍然发生了同样的情况。

这是一些丑陋的代码来重现该行为:

public class TestApp extends Application {
    public static void main(String[] args) {
        Application.launch(TestApp.class, args);
    }

    @Override
    public void start(Stage primaryStage) {
        try {
            BorderPane root = new BorderPane();
            Scene scene = new Scene(root, 400, 400);

            var flow = new FlowPane();
            flow.setOnDragOver(e -> {
                if (e.getDragboard().hasFiles()) {
                    e.acceptTransferModes(TransferMode.COPY);
                }
                e.consume();
            });

            flow.setOnDragDropped(e -> {
                var tasks = new ArrayList<TestApp.RenderTask>();
                try {
                    var document = PDDocument.load(e.getDragboard()
                                                    .getFiles().get(0));
                    var renderer = new PDFRenderer(document);
                    for (int i = 1; i <= document.getNumberOfPages(); i++) {
                        var page = document.getPage(i - 1);
                        var cropbox = page.getCropBox();
                        var thumbnailDimension = new Dimension2D(400,
                                                                 400 * (cropbox.getHeight() / cropbox.getWidth()));
                        var thumbnail = new Canvas(thumbnailDimension.getWidth(), thumbnailDimension.getHeight());
                        var gs = thumbnail.getGraphicsContext2D();
                        var pop = gs.getFill();
                        gs.setFill(Color.WHITE);
                        gs.fillRect(0, 0, thumbnailDimension.getWidth(), thumbnailDimension.getHeight());
                        gs.setFill(pop);

                        tasks.add(new TestApp.RenderTask(renderer, thumbnail, i));
                        flow.getChildren().add(new Group(thumbnail));
                    }

                    var exec = Executors.newSingleThreadExecutor();
                    tasks.forEach(exec::submit);
                    exec.submit(()-> {
                        try {
                            document.close();
                            System.out.println("close");
                        } catch (IOException ioException) {
                            ioException.printStackTrace();
                        }
                    });
                } catch (Exception ioException) {
                    ioException.printStackTrace();
                }

                e.setDropCompleted(true);
                e.consume();
            });
            var scroll = new ScrollPane(flow);
            scroll.setFitToHeight(true);
            scroll.setFitToWidth(true);
            root.setCenter(scroll);

            primaryStage.setScene(scene);
            primaryStage.show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static record RenderTask(PDFRenderer renderer, Canvas canvas, int page) implements Runnable {

        @Override
        public void run() {
            var gs = new FXGraphics2D(canvas.getGraphicsContext2D());
            gs.setBackground(WHITE);
            try {
                renderer.renderPageToGraphics(page - 1, gs);
            } catch (IOException e) {
                e.printStackTrace();
            }
            gs.dispose();
        }
    }
}

this 是我用来测试它的 310 页 PDF 文件。 谢谢

0 个答案:

没有答案
相关问题