当Window打开时,JavaFX每X ms执行一次操作

时间:2016-03-27 16:52:21

标签: user-interface asynchronous javafx

对于我的应用程序,我设计了一个由ShopLogController.java控制的简单日志窗口。

log window

此窗口获取ShopLog(不要与ShopLogController)类混淆的日志信息并显示它。但是,ShopLog本身可能会被存在的每个对象修改。因此,需要一种检查内容是否已更改的方法,以便使日志窗口的内容与ShopLog类中的文本日志保持一致。

我探索的选项:

  • update()中实现一个公共ShopLogController函数,只要日志发生变化就会调用该函数。 这很好,但IMO违反了GUI /逻辑/持久层的严格分离,因为逻辑层显式调用GUI以提示它更新。 (如果您认为这不违反分层,请解释原因)

  • 实现某种在其自己的线程中运行的更新程序对象,并且每隔X毫秒从上面调用update()。 JavaFX不允许这样生成java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-#

  • 在相应的控制器内启动一个线程。这也可以正常 ish 。唯一的问题是更新将位于永不退出的while(true)循环中。终止此循环需要一个可行的on-close方法。我不知道单个窗口的这种解决方案,而不是整个应用程序。 (见stop()

如何更新我的日志(和其他)窗口而不明确地提示它从外部这样做;同时仍然使控制器仅在关闭窗口时终止?

根据要求提供相关对象的代码:

shopLogController

shopLog

结构与此处一样基本。 String中有一个ShopLog,当它发生变化时,我希望调用update()中的ShopLogController。我还想避免从ShopLog显式调用任何控制器函数,因为不能保证存在任何控制器函数(例如,日志窗口尚未打开)。

PS:这不是关于找到any可行的解决方案,而是找到一个优雅的解决方案。

1 个答案:

答案 0 :(得分:0)

您可以像这样实现您的日志(模型):

public class ShopLog {

    private final ReadOnlyStringWrapper logText = new ReadOnlyStringWrapper();

    public ReadOnlyStringProperty textProperty() {
        return logText.getReadOnlyProperty();
    }
    public final String getText() {
        return textProperty().get();
    }

    // Implement as many methods like this as your API needs:
    public void log(String logMessage) {
        logText.set(logText.get() + "\n" + logMessage);
    }
}

显然,这个类不了解视图(或视图的控制器/演示者),因此不会违反视图和模型的分离。

您的控制器可能如下所示:

public class ShopLogController {

    private ShopLog log ;

    @FXML
    private TextArea logDisplay ;

    public void setShopLog(ShopLog log) {
        logDisplay.textProperty().bind(log.textProperty());
    }
}

现在,当log(...)上调用ShopLog方法时,视图中的文本区域会自动通知(通过绑定),并将更新显示的文本。绑定是从控制器而不是模型进行管理的,这样可以保持适当的关注点分离。完全没有必要进行任何轮询(使用任意轮询间隔和线程进行管理)。

顺便说一下,这不是一个特别可扩展的解决方案,因为您将数据存储为一个整体字符串并通过字符串连接进行更新,显示使用文本区域。我展示了这个实现,因为它似乎是你正在使用的(基于你的评论和截图)。您可以考虑使用其他常规实现,例如使用ObservableList<String> logMessages代替模型。