【问题标题】:Displaying multiple messages in JavaFX在 JavaFX 中显示多条消息
【发布时间】:2017-02-24 08:08:07
【问题描述】:

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

显而易见的事情是创建一个TextArea 并附加消息。但由于我在一些 CPU 密集型计算期间生成了它们,它们来自不同的线程。在众多答案之一中,我读到 TextArea 应该只能从主 GUI 线程访问,所以我使用 LinkedBlockingQueue 作为生产者/消费者接口。但是当我尝试使用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),然后在应用程序线程中排空并轮询它们,您仍然会得到相同的异常。

【问题讨论】:

  • 能否添加一个重现异常的MCVE

标签: java multithreading javafx textarea


【解决方案1】:

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

在未来某个未指定的时间在 JavaFX 应用程序线程上运行指定的 Runnable。此方法可以从任何线程调用,它将 Runnable 发布到事件队列,然后立即返回给调用者。 Runnables 按照它们发布的顺序执行。传递给 runLater 方法的 runnable 将在传递给后续调用 runLater 的任何 Runnable 之前执行。如果在 JavaFX 运行时关闭后调用此方法,则该调用将被忽略:不会执行 Runnable,也不会引发异常。

注意:应用程序应避免使用太多待处理的 Runnable 来淹没 JavaFX。否则,应用程序可能会变得无响应。鼓励应用程序将多个操作批处理到更少的 runLater 调用中。此外,应尽可能在后台线程上执行长时间运行的操作,从而释放 JavaFX 应用程序线程以进行 GUI 操作。

修改Run如下:

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"));
        }
    }

}

也看看这些相关的问题:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-01-02
    • 1970-01-01
    • 2013-02-07
    • 2020-12-20
    • 1970-01-01
    • 1970-01-01
    • 2017-11-25
    • 1970-01-01
    相关资源
    最近更新 更多