JavaFX 矩形不更新
JavaFX rectangle doesn't update
我正在尝试用元胞自动机做一个迷宫解析器,但我遇到了显示问题
对于每一代新的自动机网格,我们尝试以 rectangle.The 的形式显示单元格,初始化效果很好并显示网格,最后一代的模拟也显示但不显示中间步骤。
第一代图片
上一代
//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()
方法简单地启动动画并立即 returns,允许 FX 应用程序线程继续进行。当 FX 应用程序线程检查 运行ning 动画时,它将检查是否到了执行关键帧中任一处理程序的时间,如果是,则执行它们。然后它将像往常一样渲染场景。
我正在尝试用元胞自动机做一个迷宫解析器,但我遇到了显示问题
对于每一代新的自动机网格,我们尝试以 rectangle.The 的形式显示单元格,初始化效果很好并显示网格,最后一代的模拟也显示但不显示中间步骤。
第一代图片
上一代
//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()
方法简单地启动动画并立即 returns,允许 FX 应用程序线程继续进行。当 FX 应用程序线程检查 运行ning 动画时,它将检查是否到了执行关键帧中任一处理程序的时间,如果是,则执行它们。然后它将像往常一样渲染场景。