使用 JavaFX 显示 "Flash" 条消息
Show "Flash" messages with JavaFX
我的目标是拥有一个显示闪现消息(顶部的小消息,如通知)的功能,这些消息会在几秒钟后消失。我目前使用 stage
和 javafx.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();
}
我的目标是拥有一个显示闪现消息(顶部的小消息,如通知)的功能,这些消息会在几秒钟后消失。我目前使用 stage
和 javafx.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();
}