gpt4 book ai didi

java - 如何在显示 ProgressIndicator 的同时打印节点?

转载 作者:太空宇宙 更新时间:2023-11-04 14:25:48 26 4
gpt4 key购买 nike

如何在 JavaFx 中实现依赖于 GUI 组件的任务?

目标是从各种 SceneGraph 组件生成报告,同时向用户呈现一些进度指示器。

我们需要

  1. 生成某个节点的快照
  2. 将其转换为 BufferedImage
  3. 将图像传递给报告生成引擎

由于除非从 FxThread 才能更新 GUI,所以问题变为:

如何显示长时间运行的 GUI 操作的进度指示器?

我的第一种方法是将逻辑简单地放入 Task 中显然失败,导致执行 snapshot method 时出现 java.lang.IllegalStateException: Not on FX application 。它包含 Fx thread check我认为这意味着无法暂时从场景中删除节点。

使用Platform.runLater也不够,因为它只能用于写入数据到GUI,而不能读取。 (或者可以吗?)

在很短的一段时间内,我使用 SwingWorker 进行了评估,但发现与 Task 相比,它没有提供任何好处。

即使我们暂时忽略读/写问题。考虑这个例子:

package com.isp.lpt.progress;

import java.util.Random;
import java.util.concurrent.Executors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleLongProperty;
import javafx.concurrent.Task;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.effect.DropShadow;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

public class GuiTaskExample extends Application
{
private static final Random RANDOM = new Random();
private final static int WIDTH = 100;
private final static int HEIGHT = 100;

@Override
public void start( final Stage primaryStage )
{
final Group root = new Group();
final Group circleGroup = new Group();
final ProgressIndicator indicator = new ProgressIndicator();
root.getChildren().add( circleGroup );
root.getChildren().add( indicator );
final Scene scene = new Scene( root );

final GuiTaskExample that = this;
final Task<Void> task = new Task<Void>()
{
@Override
protected Void call() throws Exception
{
try (final IntStream intStream = RANDOM.ints( 1, HEIGHT ))
{
final long maxSize = HEIGHT * WIDTH;
final Stream<Circle> circles = intStream.mapToObj( that::createCircleThing ).limit( maxSize );

//local variables must be final for lambdas
final LongProperty counter = new SimpleLongProperty( 1 );

circles.forEach( circle ->
{
updateProgress( counter.get(), maxSize );
counter.set( counter.get() + 1 );
Platform.runLater( ( ) -> circleGroup.getChildren().add( circle ) );
} );

return null;
}
}
};

indicator.progressProperty().bind( task.progressProperty() );

task.setOnSucceeded( done ->
{
root.getChildren().remove( indicator );
primaryStage.sizeToScene();
} );

task.exceptionProperty().addListener( ( observable, oldValue, newValue ) -> newValue.printStackTrace() );
Executors.newSingleThreadExecutor().execute( task );

primaryStage.setScene( scene );
primaryStage.show();
}

private Circle createCircleThing( final int radius )
{
final Circle circle = new Circle();
System.out.println( radius );
circle.setRadius( RANDOM.nextInt( radius ) );
circle.setCenterX( circle.getRadius() + RANDOM.nextInt( WIDTH ) );
circle.setCenterY( circle.getRadius() + RANDOM.nextInt( HEIGHT ) );
circle.setStrokeWidth( RANDOM.nextDouble() * 4 );
circle.setStroke( randomPaint() );
circle.setFill( randomPaint() );
circle.setEffect( new DropShadow( RANDOM.nextInt( 12 ), randomPaint() ) );
return circle;
}

private Color randomPaint()
{
return Color.rgb( RANDOM.nextInt( 255 ), RANDOM.nextInt( 255 ), RANDOM.nextInt( 255 ),
RANDOM.nextDouble() );
}

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

该示例在任务中创建了大量 GUI 元素,然后将其绘制到屏幕上,但是(至少在我的机器上)绘制到屏幕上花费的时间最长,我想隐藏在进度指示器后面.

所以问题就变成了:如何在 JavaFx 中绘制到离屏缓冲区?

我愿意接受针对 Fx 中长时间运行的 GUI 操作的一般情况和/或我们使用快照的特定用例的建议。

最佳答案

对于报告部分,此 answer解决你的问题。引用的链接已损坏,但您可以找到它 here .

基本上,他使用三个子任务,其中一个用于在屏幕外场景图中创建图表(或您需要的任何其他节点)。另一种是将每个图表的快照拍摄到 JavaFX 图像,第三个将 JavaFX 图像导出到文件。或者,您也可以将这些图像传递到您的报告引擎。

关于java - 如何在显示 ProgressIndicator 的同时打印节点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26673704/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com