如何强制 Java FX 场景刷新?
Posted
技术标签:
【中文标题】如何强制 Java FX 场景刷新?【英文标题】:How to force Java FX scene refresh? 【发布时间】:2013-01-03 14:11:04 【问题描述】:我有一个 Java FX 场景,其中包含一个开始按钮和几个代表地图图块的矩形。我还绘制了一个代表我的探索者的球体(它必须探索地图),但我在运行动画时遇到了困难。
在我的开始按钮的 OnMouseClicked 处理程序中,我启动了一个用于探索地图的算法,该算法改变了球体的位置和已访问的图块的颜色。问题是算法运行时场景不会自行更新,所以我只能看到最终场景的样子(在算法停止运行之后)。如何强制更新场景,以便按顺序查看所有颜色变化?
后期编辑:
import javafx.application.Application;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.event.EventType;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class Test extends Application
private static final double boxOuterSize = 50;
private static final double boxInnerSize = 48;
private static final double boxCornerRadius = 20;
private Stage applicationStage;
private Scene applicationScene;
private static double sceneWidth = 1024;
private static double sceneHeight = 800;
private static HBox container = new HBox();
private static Group root = new Group();
private Rectangle[] rectangles = new Rectangle[10];
@Override
public void start(Stage mainStage) throws Exception
applicationStage = mainStage;
container.setSpacing(10);
container.setPadding(new Insets(10, 10, 10, 10));
try
applicationScene = new Scene(container, sceneWidth, sceneHeight);
applicationScene.addEventHandler(EventType.ROOT,(EventHandler<? super Event>)this);
applicationScene.setFill(Color.WHITE);
catch (Exception exception)
System.out.println ("exception : "+exception.getMessage());
applicationStage.setTitle("HurtLockerRobot - Tema 3 IA");
applicationStage.getIcons().add(new Image("icon.png"));
applicationStage.setScene(applicationScene);
for(int i=0; i<10; i++)
Rectangle r = new Rectangle();
r.setFill(Color.BLUE);
r.setX(i * boxOuterSize);
r.setY(0);
r.setWidth(boxInnerSize);
r.setHeight(boxInnerSize);
r.setArcHeight(boxCornerRadius);
r.setArcWidth(boxCornerRadius);
r.setSmooth(true);
rectangles[i] = r;
root.getChildren().add(rectangles[i]);
container.getChildren().add(root);
Button startButton = new Button("Start");
startButton.setOnMouseClicked(new EventHandler<Event>()
@Override
public void handle(Event arg0)
for(int i=0; i<10; i++)
rectangles[i].setFill(Color.RED);
// TODO: some kind of scene refresh here
);
container.getChildren().add(startButton);
applicationStage.show();
public static void main(String[] args)
launch(args);
最初所有的矩形都是蓝色的。我想在这里获得的行为是看到矩形按顺序改变颜色。问题是我只能看到最终结果(所有矩形同时改变颜色)。
【问题讨论】:
如需尽快获得更好的帮助,请发帖SSCCE 我添加了一些代码来显示我想要获得的行为类型。我希望现在更清楚了。 我的意思是:短,自包含,正确(可编译),示例 对不起,我最初认为只编写 EventHandler 就足够了。然后我阅读了有关 SSCCE 的信息并更正了帖子。 【参考方案1】:这是一个老问题,它引起了我的注意,因为这是 JavaFX 新手面临的一个非常普遍的问题。
OP 面临的问题是因为他一次更新所有矩形,无需等待。
OP 可以通过创建一个新线程来等待,在每次循环迭代时将线程置于睡眠状态估计几秒钟,然后使用Platform.runLater
更新 JavaFX 应用程序线程上矩形的颜色。
@Override
public void handle(Event arg0)
new Thread(() ->
for(int i=0; i<10; i++)
try
Thread.sleep(1000); // Wait for 1 sec before updating the color
catch (InterruptedException e)
e.printStackTrace();
int finalI = i;
Platform.runLater(() -> rectangles[finalI].setFill(Color.RED));// Update on JavaFX Application Thread
).start();
上面的sn-p更像是一种传统的做事方式。如果我们想使用“JavaFX”的方式做事,我们可以通过使用Animation
来实现。
下面是一个代码 sn-p,它将在更改矩形颜色之前等待x-seconds
。它不需要任何额外的线程,因为等待由为每个矩形应用的PauseTransition
处理。
startButton.setOnMouseClicked(new EventHandler<Event>()
@Override
public void handle(Event arg0)
for(int i=0; i<10; i++)
PauseTransition pauseTransition = new PauseTransition(Duration.seconds(i));
int finalI = i;
pauseTransition.setOnFinished(event -> rectangles[finalI].setFill(Color.RED));
pauseTransition.play();
);
它为每个矩形创建一个 PauseTransition,并根据其在数组 rectangles
中的索引,在更新颜色之前等待相同的秒数。
【讨论】:
【参考方案2】:这是因为:
exception : Test cannot be cast to javafx.event.EventHandler
好吧,我不知道 Class cast 异常是怎么出现的。
否则,要延迟,可以使用Thread.sleep()
。
更新:
用AnimationTimer创建动画就好了,不需要刷新任何东西。
在这里,我用FillTransition
做了一个简短的 EG 来显示颜色矩形。
代码:
import javafx.animation.FillTransition;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class NewFXMain1 extends Application
private static final double boxOuterSize = 50;
private static final double boxInnerSize = 48;
private static final double boxCornerRadius = 20;
private Rectangle rectangles = new Rectangle();
public static void main(String[] args)
launch(args);
@Override
public void start(Stage primaryStage)
primaryStage.setTitle("rect");
Button btn = new Button();
StackPane root = new StackPane();
Rectangle r = new Rectangle();
r.setFill(Color.BLUE);
r.setX(2 * boxOuterSize);
r.setY(0);
r.setWidth(boxInnerSize);
r.setHeight(boxInnerSize);
r.setArcHeight(boxCornerRadius);
r.setArcWidth(boxCornerRadius);
r.setSmooth(true);
r.localToScene(boxOuterSize, boxOuterSize);
rectangles = r;
root.getChildren().add(rectangles);
btn.setText("display");
btn.setOnAction(new EventHandler<ActionEvent>()
@Override
public void handle(ActionEvent event)
FillTransition ft = new FillTransition(Duration.millis(3000), rectangles, Color.RED, Color.BLUE);
ft.setCycleCount(4);
ft.setAutoReverse(true);
ft.play();
);
root.getChildren().add(btn);
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
【讨论】:
该异常出现在那里,因为我忘记删除带有 addEventHandler 的行。无论如何,该异常不会以任何方式影响应用程序或我面临的问题(它在新场景之后被抛出......)。 Thread.sleep() 不是解决方案,因为它使 GUI JavaFX 线程进入睡眠状态,因此肯定无法正常工作(如果 GUI 线程处于睡眠状态,如何刷新 GUI?)。 我的意思是暂停一下,比如 100 毫秒,然后为另一个矩形着色 运行事件处理程序的线程是 Java FX 线程。该线程还进行场景的渲染。所以如果我暂停这个线程,那也意味着场景不会被刷新。 您提供的示例对我的问题没有帮助。正如我之前提到的,我想在这里获得的行为是看到矩形按顺序改变颜色。此外,如果我使用 AnimationTimer,我仍然会遇到所有动画同时运行的问题。 @Nikopol 不,如果您使用动画计时器,您不会有任何问题。如果您有任何问题,请尝试发布 sscce以上是关于如何强制 Java FX 场景刷新?的主要内容,如果未能解决你的问题,请参考以下文章