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