[英]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.