Use of Thread.sleep() in JavaFx Application

Đặng Huy :

I try to make an application that shows a button. When I click the button, the scene should show some text (add a label) for a few seconds, and then the text should disappear (removing the label from the scene). But in fact when I click the button, nothing happens.

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        StackPane pane = new StackPane();
        Button btn = new Button();
        Label lb = new Label("Start");
        pane.getChildren().addAll(btn);
        primaryStage.setTitle("Hello World");
        primaryStage.setScene(new Scene(pane, 300, 275));
        primaryStage.show();
        btn.setOnAction(e->{
             pane.getChildren().addAll(lb);
            try {
                Thread.sleep(300);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
           pane.getChildren().removeAll(lb);
        });
    }
    public static void main(String[] args) {
        launch(args);
    }
}
James_D :

Use a PauseTransition:

btn.setOnAction(e->{
    pane.getChildren().addAll(lb);
    PauseTransition pause = new PauseTransition(Duration.seconds(0.3));
    pause.setOnFinished(e -> pane.getChildren().removeAll(lb));
    pause.play();
});

The reason your approach doesn't work, is that JavaFX effectively uses a single thread for rendering and handling user events. It will update the screen at a fixed interval (60 times per second in the current implementation), but for synchronization reasons has to wait for any pending events that are currently being handled to complete first. So you original code adds the label, pauses for 0.3 seconds, and then removes the label. The FX Application Thread is occupied for this whole process, so the FX framework never has an opportunity to redraw the scene while it is happening.

The bottom line here is that you should never block the FX application thread, by calling sleep() or by executing long-running operations.

Update in response to additional question in comment:

To disable all event handling, you can call setDisable(true) on the root node of the scene. So to prevent event handling while the label is shown:

btn.setOnAction(e->{
    pane.getChildren().addAll(lb);
    pane.setDisable(true);
    PauseTransition pause = new PauseTransition(Duration.seconds(0.3));
    pause.setOnFinished(e -> {
        pane.getChildren().removeAll(lb));
        pane.setDisable(false);
    });
    pause.play();
});

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=400684&siteId=1