我是JavaFX的新手,在使用ControlsFX Notification时遇到了一个小问题。在一些较长时间运行的任务(例如下载某些文件)期间,我希望在下载开始时显示通知,并在完成时再次显示通知;但是,当我尝试这个时,通知只会在任务完成后显示。
这是一个使用Thread.Sleep模拟某些代码运行延迟的示例:
Notifications.create() .title("Title Text") .text("Hello World 1!") .darkStyle() .show();
Thread.sleep(500);
Notifications.create() .title("Title Text") .text("Hello World 2!") .darkStyle() .show();
Thread.sleep(500);
Notifications.create() .title("Title Text") .text("Hello World 3!") .darkStyle() .show();
Thread.sleep(500);
运行时,会立即显示所有通知,而不是半秒。
Here's an image of what the notifications look like in the lower right corner
However, they fade away a half second apart..
所以它们相隔500毫秒创建,但不会立即显示。我如何让它们立即显示?
答案 0 :(得分:2)
在您的代码中,您将阻止负责重绘UI的JavaFX应用程序线程。这样,GUI中的任何更改都不会显示,事件也不会被处理,等等。
您可以使用Task
并在message
属性中添加一个侦听器以显示消息。保证在应用程序线程上执行此属性的更新。唯一的缺点是,为了快速更新属性,可以跳过一些通知。
Task<Void> task = new Task<Void>() {
@Override
protected Void call() throws Exception {
// update message property
updateMessage("Hello World 1!");
Thread.sleep(500);
updateMessage("Hello World 2!");
Thread.sleep(500);
updateMessage("Hello World 3!");
Thread.sleep(500);
return null;
}
};
// display message changes as notifications
task.messageProperty().addListener((observable, oldMessage, newMessage) ->
Notifications.create().title("Title Text").text(newMessage).darkStyle().show());
// execute long running task on background thread
new Thread(task).start();
如果您需要显示每条消息,则应使用Platform.runLater
来触发通知。
Thread thread = new Thread(new Runnable() {
private void postMessage(final String message) {
Platform.runLater(() -> Notifications.create().title("Title Text").text(message).darkStyle().show());
}
@Override
public void run() {
try {
postMessage("Hello World 1!");
Thread.sleep(500);
postMessage("Hello World 2!");
Thread.sleep(500);
postMessage("Hello World 3!");
Thread.sleep(500);
} catch (InterruptedException ex) {
Logger.getLogger(NotificationsTestMain.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
thread.start();
请注意,您应该注意不要经常使用Platform.runLater
。如果有很多更新,有时最好对它们进行分组。但是在这种情况下,您可能不想使用通知,因为只需要很多人来显示所有这些通知。尽管如此,这里还有一些代码可以对更新进行分组:
private final List<String> messageQueue = new ArrayList<>();
private boolean updating;
private final Runnable updater = () -> {
synchronized (messageQueue) {
for (String message : messageQueue) {
Notifications.create().title("Title Text").text(message).darkStyle().show();
}
messageQueue.clear();
updating = false;
}
};
private void postMessage(String message) {
synchronized (messageQueue) {
messageQueue.add(message);
if (!updating) {
updating = true;
Platform.runLater(updater);
}
}
}
答案 1 :(得分:0)
您没有显示任何上下文,但我说您的代码只是阻止了JavaFX GUI线程。您必须在单独的线程中执行上面的代码,并将每个通知创建包装在Platform.runLater调用中。 或者,您也可以使用AnimationTimer或Timeline。然后你不需要一个单独的线程而没有Thread.sleep。