问题描述
我正在尝试使用蜂窝自动机来做一个迷宫解析器,但是显示有问题对于每一个新一代的自动机网格,我们尝试以矩形形式显示单元格.初始化工作良好,并且显示了网格,也显示了最后一代模拟,但没有显示中间步骤.
I'm trying to do a maze resolver with a cellular automaton but I have a display problemfor each new generation of a grid of an automaton we try to display the cells in the form of rectangle.The initialization works well and the grid is displayed,the last generation of the simulation is displayed too but not the intermediate steps.
第一代图片
上一代
//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);
}
要启动下一代,请按一个按钮.
to start the next generation you press a button.
//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
the problem seems to be that we are stuck in the method setOnMouseClicked() and that the update of the rectangles is not done, with a textual display I see the evolution of the automaton which indicates us that the simulation works and that the problem seems to come from JavaFX
推荐答案
JavaFX Application Thread作为循环运行.有效地(实际的实现细节要复杂得多),循环可以执行以下操作(以伪代码方式):
The JavaFX Application Thread runs as a loop. Effectively (the actual implementation details are far more complex) that loop does the following (in pseudocode):
while (applicationIsRunning()) {
if (thereAreEventsToHandle()) {
handleEvents();
}
if (thereAreAnimationsToUpdate()) {
updateAnimations();
}
if (itsTimeToRenderTheScene()) {
renderScene();
}
}
默认情况下,JavaFX每秒最多可渲染场景60次.
By default, JavaFX renders the scene at most 60 times per second.
事件处理程序中的代码在FX Application线程上执行(由上面的伪代码循环中的第一个块调用).由于FX Application Thread在该线程上处于休眠状态,因此在整个事件处理程序完成之前,它永远不会到达循环的第三部分(渲染场景).因此,您永远不会看到中间更新,因为永远不会渲染场景.
The code in your event handler is executed on the FX Application Thread (it's invoked by the first block in the pseudocode loop above). Since it sleeps on that thread, the FX Application Thread never gets to the third part of the loop (rendering the Scene) until the entire event handler completes. Consequently, you never see the intermediate updates, because the scene is never rendered.
假设mazeA.nextStep()
不会阻塞(或花费很长时间运行),最好将其重构为Animation
,例如Timeline
:
Assuming mazeA.nextStep()
doesn't block (or take a long time to run), it's best to refactor this as an Animation
, e.g. a 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()
方法只是启动动画并立即返回,从而允许FX Application Thread继续进行.当FX Application Thread检查正在运行的动画时,它将检查是否是时候执行关键帧中的两个处理程序,如果是,则执行它们.然后它将照常渲染场景.
The timeline.play()
method simply starts the animation and returns immediately, allowing the FX Application Thread to proceed. When the FX Application Thread checks for running animations, it will check if it's time to execute either of the handlers in the key frames, and if so will execute them. Then it will render the scene as usual.
这篇关于JavaFX矩形不会更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!