java - 在 JavaFX 中显示多条消息

标签 java multithreading javafx textarea

在 JavaFX 的 GUI 中显示多条消息的推荐方法是什么?

显而易见的事情是创建一个 TextArea并添加消息。但由于我在一些 CPU 密集型计算期间生成了它们,因此它们来自不同的线程。在众多答案之一中,我读到 TextArea 只能从主 GUI 线程访问,所以我使用了 LinkedBlockingQueue作为生产者/消费者接口(interface)。但是当我尝试使用 TimerscheduleAtFixedRate 附加消息时,我遇到了更多错误,如下所示:

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
    at com.sun.javafx.text.PrismTextLayout.getRuns(PrismTextLayout.java:236)
    at javafx.scene.text.Text.getRuns(Text.java:317)
    at javafx.scene.text.Text.updatePGText(Text.java:1465)
    at javafx.scene.text.Text.impl_updatePeer(Text.java:1500)
    at javafx.scene.Node.impl_syncPeer(Node.java:503)
    at javafx.scene.Scene$ScenePulseListener.synchronizeSceneNodes(Scene.java:2290)
    at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2419)
    at com.sun.javafx.tk.Toolkit.lambda$runPulse$30(Toolkit.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:354)
    at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:381)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:510)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:490)
    at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$404(QuantumToolkit.java:319)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
    at java.lang.Thread.run(Thread.java:745)
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
    at javafx.scene.Scene$ScenePulseListener.synchronizeSceneNodes(Scene.java:2289)
    at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2419)
    at com.sun.javafx.tk.Toolkit.lambda$runPulse$30(Toolkit.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:354)
    at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:381)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:510)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:490)
    at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$404(QuantumToolkit.java:319)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
    at java.lang.Thread.run(Thread.java:745)

我认为问题可能是 FX 应用程序线程充斥着太多消息。但必须有一些推荐的方法来做到这一点。对吗?

MCVE:

public class MCVE extends Application {    
    @Override
    public void start(Stage primaryStage) {
        TextArea ta = new TextArea();
        StackPane root = new StackPane();
        root.getChildren().add(ta);
        Scene scene = new Scene(root, 800, 650);
        primaryStage.setScene(scene);
        primaryStage.show();

        Run.ta = ta;
        new Thread(new Run()).start();

    public static void main(String[] args) {
        launch(args);
    }

    static class Run implements Runnable{
        public static TextArea ta;
        @Override
        public void run() {
            for (int i = 0; i < 1000000000; i++) {
                ta.appendText("lahsdvl lefwq gwlqwkjgl kqwldfwkhevf.");
            }
        }
    }
}

如果将字符串添加到 BlockingQueue(而不是在 Run 中追加),然后在应用程序线程中排出并轮询它们,您仍然会得到相同的异常。

最佳答案

您可以使用Platform#runLater(Runnable)从另一个线程更新 GUI:

Run the specified Runnable on the JavaFX Application Thread at some unspecified time in the future. This method, which may be called from any thread, will post the Runnable to an event queue and then return immediately to the caller. The Runnables are executed in the order they are posted. A runnable passed into the runLater method will be executed before any Runnable passed into a subsequent call to runLater. If this method is called after the JavaFX runtime has been shutdown, the call will be ignored: the Runnable will not be executed and no exception will be thrown.

NOTE: applications should avoid flooding JavaFX with too many pending Runnables. Otherwise, the application may become unresponsive. Applications are encouraged to batch up multiple operations into fewer runLater calls. Additionally, long-running operations should be done on a background thread where possible, freeing up the JavaFX Application Thread for GUI operations.

调整运行如下:

static class Run implements Runnable {

    public static TextArea ta;

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            Platform.runLater(() -> ta.appendText("Lorem ipsum.\n"));
        }
    }

}

另请查看这些相关问题:

关于java - 在 JavaFX 中显示多条消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40050839/

相关文章:

java - SWT - 获取图像的实际屏幕位置

java - "see"Java标准库可以离线吗

java - 从编辑控件向上传递上下文菜单快捷方式

java - 使用 Visual Studio Code 远程扩展运行 JavaFX

java - 如何在 javafx 中使用 fxml 创建自定义弹出窗口?

JavaFX:从 ProgressIndicator 中删除百分比

java - 将加密/解密 key 存储到静态变量中是否安全?

python - 在 Python 中记录特定于线程和共享的日志文件

c++ - 尝试使用 std::thread 时出现编译器错误

java - 死线程是内存泄漏的威胁吗?