What is the recommended way to display multiple messages in GUI in JavaFX?
The obvious thing would be to create a TextArea
and just append messages. But since I have them generated during some CPU intensive computations, they come from a different thread. In one of many answers I read that TextArea
should be accessed only from Main GUI Thread, so I used LinkedBlockingQueue
as a Producer/Consument interface. But when I tried to append messages using Timer
's scheduleAtFixedRate
, I ran into more errors, like this:
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)
I think the problem may be flooding the FX Application Thread with too many messages. But there must be some recommended way to do this. Right?
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.");
}
}
}
}
If you add Strings to BlockingQueue (instead of appending in Run
) and then drain & poll them in Application Thread, you still get the same Exception.