首页 > 解决方案 > 在 JavaFx 应用程序中使用 Thread.sleep()

问题描述

我尝试制作一个显示按钮的应用程序。当我单击按钮时,场景应该显示一些文本(添加标签)几秒钟,然后文本应该消失(从场景中删除标签)。但事实上,当我点击按钮时,什么也没有发生。

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);
    }
}

标签: javamultithreadingjavafx

解决方案


使用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();
});

您的方法不起作用的原因是 JavaFX 有效地使用单个线程来呈​​现和处理用户事件。它将以固定的时间间隔更新屏幕(在当前实现中每秒 60 次),但出于同步原因,必须等待当前正在处理的任何未决事件首先完成。因此,您的原始代码添加标签,暂停 0.3 秒,然后删除标签。FX 应用程序线程被整个过程占用,因此 FX 框架永远没有机会在场景发生时重绘场景。

这里的底线是,您永远不应该通过调用sleep()或执行长时间运行的操作来阻塞 FX 应用程序线程。

更新以回应评论中的其他问题:

要禁用所有事件处理,您可以调用setDisable(true)场景的根节点。因此,为了防止在显示标签时进行事件处理:

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();
});

推荐阅读