Javafx controlsfx调用show()时,通知不会立即显示

时间:2016-10-22 19:12:35

标签: javafx notifications controlsfx

我是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毫秒创建,但不会立即显示。我如何让它们立即显示?

2 个答案:

答案 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。