Javafx controlsfx通知不';调用show()时不立即显示

Javafx controlsfx通知不';调用show()时不立即显示,javafx,notifications,controlsfx,Javafx,Notifications,Controlsfx,我是JavaFX新手,在使用ControlsFX通知时挂断了一个小问题。在一些长时间运行的任务(例如下载一些文件)中,我希望在下载开始时显示通知,在下载完成时再次显示通知;但是,当我尝试此操作时,这两个通知仅在任务完成后显示 下面是Thread.Sleep的一个示例,它模拟了某些代码运行的延迟: Notifications.create() .title("Title Text") .text("Hello World 1!") .darkStyle() .show(); Thread.sl

我是JavaFX新手,在使用ControlsFX通知时挂断了一个小问题。在一些长时间运行的任务(例如下载一些文件)中,我希望在下载开始时显示通知,在下载完成时再次显示通知;但是,当我尝试此操作时,这两个通知仅在任务完成后显示

下面是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);
运行此操作时,所有通知同时显示,间隔不到半秒


因此,它们被创建时相隔500毫秒,但不会立即显示。如何让它们立即显示?

您没有显示任何上下文,但我认为您的代码只是阻塞了JavaFXGUI线程。您必须在单独的线程中执行上述代码,并将每个通知创建包装在Platform.runLater调用中。
或者,您也可以使用AnimationTimer或Timeline。这样就不需要单独的线程,也不需要线程。sleep。

在代码中,您可以阻止负责重新绘制UI的JavaFX应用程序线程。这样,GUI中的任何更改都将不可见,事件也不会被处理,等等

您可以使用
任务
并将侦听器添加到
消息
属性中,以显示消息。此属性的更新保证在应用程序线程上执行。唯一的缺点是,对于属性的快速更新,可以跳过一些通知

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
。如果有很多更新,有时最好将它们分组。不过,在这种情况下,您可能无论如何都不想使用通知,因为显示所有通知的数量太多了。以下是一些演示如何对更新进行分组的代码:

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);
        }
    }
}
private final List messageQueue=new ArrayList();
私有布尔更新;
私有最终可运行更新程序=()->{
已同步(消息队列){
for(字符串消息:messageQueue){
Notifications.create().title(“title Text”).Text(message).darkStyle().show();
}
messageQueue.clear();
更新=假;
}
};
私有void postMessage(字符串消息){
已同步(消息队列){
messageQueue.add(message);
如果(!正在更新){
更新=真;
runLater(更新程序);
}
}
}

啊,是的,我完全忘记了平台。请稍后运行。我确实尝试过,但遇到的问题是,所有通知都将在应用程序线程完成后创建。通过以上操作,它们将分别创建,并同时显示在末尾。因此,第一个(应显示3秒钟)必须等待三个睡眠呼叫,然后出现,但仅显示1.5秒钟。如果我使用platform.runLater,所有三个都会出现并停留3秒钟,但它们只有在应用程序线程完成后才能同时创建。使用Timeline,我遇到了与platform.runLater相同的问题。所有三个都是在应用程序线程完成其所做的任何事情后创建和显示的。在我的问题中,我使用了Thread.sleep,但我的实际应用程序下载了一些文件并进行了一些其他的文件处理。我希望它能够通知“开始下载”然后“下载完成”等等。因此,在最后一次向用户显示所有通知显然不是很有用。我不熟悉时间线,所以我将稍微玩一下它,看看是否能让它按我想要的方式运行。@docb45
Timeline
是个坏主意(不知何故,我没有适当注意“Thread.Sleep simulating a delay”部分)。修改了答案…效果惊人!我玩了Task,但是我缺少了添加一个侦听器来显示通知的部分。这非常有效。当updateMessage和updateProgress很容易失去同步并且不能在短时间内处理多个事件/消息时,为什么还要麻烦它们呢?在我看来,JavaFX的设计很糟糕。
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);
        }
    }
}