[英]JavaFX rectangle doesn't update
我正在尝试使用元胞自动机做一个迷宫解析器,但是对于自动机的每一代新一代网格都有一个显示问题,我们尝试以矩形的形式显示单元格。初始化效果很好,并且显示了网格,最后一代的模拟也显示,但不显示中间步骤。
第一代图片
上一代
//Initialise la liste des rectangles
public void initRectList() {
for(int height = 0; height < this.mazeA.grid.getHeight(); height++) {
for(int width = 0; width < this.mazeA.grid.getWidth(); width++) {
this.rectList[height][width] = new Rectangle(REC_HEIGHT,REC_WIDTH, getColorCell(this.mazeA.grid, height, width));
}
}
}
//Dessine le labyrinthe
public void drawGrid() {
for (int height = 0; height < this.mazeA.grid.getHeight(); height++) {
for(int width = 0; width < this.mazeA.grid.getWidth(); width++) {
tilePane.getChildren().add(this.rectList[height][width]);
}
}
}
public class MazeFX {
private HBox root = new HBox();
private Scene scene = new Scene(root,1100,800);
private TilePane tilePane = new TilePane();
private Grid grid = new Grid(30,30);
private Rectangle[][] rectList = new Rectangle[30][30];
private VBox buttons = new VBox();
private Button reset = new Button("Reset");
private Button pas = new Button("Play");
private Button load = new Button("Load");
private MazeAutomaton mazeA;
private final double REC_HEIGHT = 20.;
private final double REC_WIDTH = 20.;
public MazeFX(Stage stage) throws InterruptedException {
scene.getStylesheets().add(getClass().getResource("/src/application.css").toExternalForm());
initButton();
initLayout();
initGridByTopologie();
mazeA = new MazeAutomaton(this.grid);
initRectList();
drawGrid();
pressedButtons(stage);
setWindow(stage);
displayWindow(stage);
}
开始下一代你按下一个按钮。
//Action de l'utilisateur sur l'un des bouttons
public void pressedButtons(Stage stage) {
pressReset();
pressPAS();
pressLoad(stage);
}
//Boutton Play/Stop préssé
public void pressPAS() {
this.pas.setOnMouseClicked(e -> {
for (int i = 0; i < 30; i++) {
mazeA.nextStep();
try {
Thread.sleep(100);
} catch (InterruptedException interruptedException) {
interruptedException.printStackTrace();
}
updateRectColor();
}
}
);
}
问题似乎是我们被困在方法 setOnMouseClicked() 并且矩形的更新没有完成,通过文本显示我看到了自动机的演变,这表明我们模拟有效并且问题似乎来自 JavaFX
JavaFX 应用程序线程作为循环运行。 实际上(实际的实现细节要复杂得多)该循环执行以下操作(在伪代码中):
while (applicationIsRunning()) {
if (thereAreEventsToHandle()) {
handleEvents();
}
if (thereAreAnimationsToUpdate()) {
updateAnimations();
}
if (itsTimeToRenderTheScene()) {
renderScene();
}
}
默认情况下,JavaFX 每秒最多渲染场景 60 次。
事件处理程序中的代码在 FX 应用程序线程上执行(由上面伪代码循环中的第一个块调用)。 由于它在该线程上休眠,因此在整个事件处理程序完成之前,FX 应用程序线程永远不会到达循环的第三部分(渲染场景)。 因此,您永远不会看到中间更新,因为场景永远不会被渲染。
假设mazeA.nextStep()
不会阻塞(或需要很长时间才能运行),最好将其重构为Animation
,例如Timeline
:
public void pressPAS() {
this.pas.setOnMouseClicked(e -> {
KeyFrame updateMaze = new KeyFrame(Duration.ZERO, evt -> mazeA.nextStep());
KeyFrame updateRect = new KeyFrame(Duration.millis(100), evt -> updateRectColor());
Timeline timeline = new Timeline(updateMaze, updateRect);
timeline.setCycleCount(30);
timeline.play();
});
}
timeline.play()
方法简单地启动 animation 并立即返回,允许 FX 应用程序线程继续。 当 FX 应用程序线程检查正在运行的动画时,它会检查是否该执行关键帧中的任一处理程序,如果是则执行它们。 然后它会像往常一样渲染场景。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.