在JavaFx应用中使用Thread.sleep()。

huangapple go评论71阅读模式
英文:

Use of Thread.sleep() in JavaFx Application

问题

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

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("开始");
        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);
    }
}
英文:

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

答案1

得分: 4

使用 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 Application Thread 都被占用,因此 FX 框架在此过程中没有机会重新绘制场景。

总之,你不应该阻塞 FX 应用程序线程,即不要调用 sleep() 或执行长时间运行的操作。

针对评论中的附加问题的更新:

要禁用所有事件处理,你可以在场景的根节点上调用 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();
});
英文:

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

huangapple
  • 本文由 发表于 2020年4月3日 20:44:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/61012205.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定