我有一个应用程序,我想在其中显示一个 FlowPane
,其中包含绘制到画布中的 PDF 页面缩略图。我正在使用 PDFBox 和 FXGraphics2D 来呈现页面。
我当前的实现创建了许多画布作为页面数,将它们添加到 FlowPane
,然后旋转多个或异步任务以将页面内容绘制到画布中。
我不确定异步绘图是否是推荐的方式,但我的想法是不使用 JavaFX 线程进行 PDF 解析以避免冻结应用程序。 现在,我的问题是这样的,我可以从日志中看到所有渲染任务都已完成并且文档已关闭。 UI 显示了一些呈现的页面,但它保持无响应约 10 秒。之后应用程序恢复,所有页面都被呈现并且一切正常。
我尝试分析,我认为这是相关部分: 但是我对引擎盖下发生的事情的了解有限,我无法弄清楚我做错了什么。您对我的方法/代码有什么问题以及如何改进有任何想法或提示吗?理想情况下,我希望在填充页面缩略图时应用程序快速响应。
我在 Linux 上使用一台相当不错的机器,但我也在 Windows 上进行了测试并得到了相同的行为。我还尝试将 FlowPane
替换为 HBox
或 VBox
,但仍然发生了同样的情况。
这是一些丑陋的代码来重现该行为:
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 文件。 谢谢