使用 JavaFX 显示 "Flash" 条消息

Show "Flash" messages with JavaFX

我的目标是拥有一个显示闪现消息(顶部的小消息,如通知)的功能,这些消息会在几秒钟后消失。我目前使用 stagejavafx.concurrent.Task:

    public static void showFlashMessage(String message) {

        Stage window = new Stage();
        window.initStyle(StageStyle.UNDECORATED);

        ...

        Scene scene = new Scene(layout);
        window.setScene(scene);
        window.show();

        Task<Void> task = new Task<>() {
            @Override
            protected Void call() throws Exception {
                Thread.sleep(3000);
                return null;
            }
        };
        task.setOnSucceeded(e -> {
            window.close();
        });
        new Thread(task).start();
    }

但是当用户点击主舞台时,闪现消息消失了。调用 window.toFront() 只会将 window 移动到前面的。 我希望此消息在任何地方看起来都一样,例如 Alert 中的构建,但此外我无法设置 window.initModality(Modality.APPLICATION_MODAL),因为这不允许与主舞台进行交互。 有没有好的方法来实现这一目标?我几乎无法在现有布局中显示这些消息,它们的结构非常不同,而且到处看起来都不一样。舞台的第二个好处是,它在后台布局更改后仍然存在。

要使其按您希望的方式运行,您可以指定舞台的所有者 Window。这必须在舞台可见之前发生。

window.initOwner(ownerStage);

否则你也可以考虑将 Window 设置为总在最前面。

window.setAlwaysOnTop(true); 

您可能还想看看这个 post:

其中展示了如何制作 Android 风格的吐司。

如前所述,设置 Stage.setAlwaysOnTop(true) 即可。

虽然 Task 有效,但对于纯屏幕动画,您可能应该坚持使用 JavaFX 动画工具。时间轴在这里工作得很好,并且还允许您通过在布局上进行轻微的淡入和淡出来使 Flash 消息更加流畅。像这样:

   private void showFlashMessage(String message) {
        Stage window = new Stage();
        window.initStyle(StageStyle.TRANSPARENT);
        VBox layout = new VBox(10, new Text(message));
        layout.setPadding(new Insets(3));
        layout.setBackground(new Background(new BackgroundFill(Color.PINK, new CornerRadii(3), Insets.EMPTY)));
        window.setScene(new Scene(layout, Color.TRANSPARENT));
        window.setAlwaysOnTop(true);
        Timeline timeline = new Timeline(new KeyFrame(Duration.ZERO, evt -> window.show(), new KeyValue(layout.opacityProperty(), 0)),
                                         new KeyFrame(Duration.millis(200), new KeyValue(layout.opacityProperty(), 1.0)),
                                         new KeyFrame(Duration.millis(2600), new KeyValue(layout.opacityProperty(), 1.0)),
                                         new KeyFrame(Duration.millis(3000), new KeyValue(layout.opacityProperty(), 0.2)));
        timeline.setOnFinished(evt -> window.close());
        timeline.play();
    }