【问题标题】:What is the best way to update a TextArea from a Task line by line?从任务逐行更新 TextArea 的最佳方法是什么?
【发布时间】:2019-03-14 05:13:50
【问题描述】:

我正在从我的应用程序执行一个脚本,并通过任务值属性上的更改侦听器使用输出更新文本区域,但并非所有行都显示出来。

this.valueProperty().addListener(new ChangeListener<String>() {

    @Override
    public void changed(ObservableValue observable, String oldValue, String newValue) {
        if (!(newValue == null)) {
            output.appendText(newValue + "\n");
        }
    }

});

JavaFX ChangeListener not always working 基本上回答了我的问题,但我有一个后续问题。

在调用 updateValue() 之前或之后休眠任务似乎有我想要的连续附加结果的输出,但我不明白如何。随着睡眠时间越来越短,结果越来越不完整。如果任务处于睡眠状态,它不会在它停止的地方继续,我不会看到任何行为差异吗?因为合并的值属性没有改变?

或者睡眠线程是否保证值不会在另外 250 毫秒内更新,同时 UI 线程正在更新?这给了 UI 线程足够的时间来捕获每一行?这似乎不是一种非常可靠的更新方式,因为我怎么知道需要多少时间才能获得完整的输出?

    while ((line = outputReader.readLine()) != null) {
        updateValue(line);
        Thread.sleep(250);
    }

我尝试在读取每一行后直接通过 Platform.runLater 更新 TextArea,但我收到错误“从内部类引用的局部变量”,我不知道如何解决这个问题。 TexArea 是我的扩展 Task 类的一个实例变量,它不是最终的,因为我正在附加字符串,所以我不知道如何解决它。

【问题讨论】:

  • 尝试用Platform.runLater() 调用updateValue()(即Platform.runLater(() -&gt; updateValue(line))
  • 我得到“从内部类引用的局部变量”错误。也许我需要让文本区域成为一个单独的类,而不是我的客户任务类中的一个变量。
  • 局部变量错误与文本区域无关。这是因为“line”变量没有像fabian的回答那样变成最终变量。

标签: java javafx task


【解决方案1】:

Task.updateValue 确保将来会进行更新。由于安排这些更新的成本很高,它只是确保对最后传递的值进行更新。它的工作原理与此类似

void updateValue(T value) {
    setNewValue(value);
    if (lastUpdateFinished()) {
        Platform.runLater(() -> doUpdate());
    }
}

其中lastUpdateFinished 返回false 当且仅当存在尚未检索新值的计划更新。从理论上讲,没有多少睡眠可以保证防止问题发生,但实际上你睡得越久,lastUpdateFinished() 越有可能在每次调用updateValue 时产生true...


在您的情况下,Platform.runLater 需要多次使用以确保应用程序线程看到每一次更新:

String line;
while ((line = outputReader.readLine()) != null) {
    final String lineFinal = line + "\n";
    Platform.runLater(() -> output.appendText(lineFinal));
}

请注意,如果更新过于频繁,这可能会减慢 JavaFX。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-10
    • 2019-10-30
    相关资源
    最近更新 更多