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();
}
}
By default, JavaFX renders the scene at most 60 times per second.
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.
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();
});
}
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.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…