Hello,大家好。我是 78KgMiao。
相信很多使用JavaFx的小伙伴都遇到過這個問題。Not on FX application thread;
造成這個問題的原因呢,就是沒有在JavaFx的UI線程中繪制。
不管是JavaSwing也好,JavaFx也罷。都會把UI繪制放到一個獨立的線程中。避免其他線程去刷新UI。如果說外部線程可以繪制UI的話,那不就亂套了嗎。
代碼案例
package com.beishu.clip.text;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class NotonFX extends Application {
@Override
public void start(Stage stage) throws Exception {
Pane root = new Pane();
Scene scene = new Scene(root, 500, 300);
stage.setTitle("Not on FX application thread");
stage.setScene(scene);
stage.show();
new Thread(() -> {
// TODO 耗時操作...
VBox pane = new VBox();
pane.getChildren().add(new Label("78KgMiao"));// 1
pane.getChildren().add(new TextField("78KgMiao"));// 2
// root.getChildren().add(pane);// 3 此處會報錯
// 4 更新UI
Platform.runLater(() -> {
root.getChildren().add(pane);
});
}).start();
}
public static void main(String[] args) {
launch(args);
}
}
異常堆棧信息
Exception in thread "Thread-3" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-3
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:291)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:446)
at javafx.scene.Parent$3.onProposedChange(Parent.java:474)
at com.sun.javafx.collections.VetoableListDecorator.add(VetoableListDecorator.java:206)
at com.beishu.clip.text.NotonFX.lambda$0(NotonFX.java:30)
at java.base/java.lang.Thread.run(Thread.java:834)
案例分析
案例很簡單,創建了一個VBox
,然后分別在1
和2
處添加一個Label
和一個TextField
。如果打開注釋3
,那么會報如上錯誤信息。解決辦法就是用注釋4
處的方法。
那么是不是所有的類似add, addAll
等方法都需要使用Platform.runLater(() -> {//TODO});
處理呢?參考注釋1,2
,你會發現其實不是這樣的。
教大家一個判斷標准:
如果這一行代碼運行之后,頁面的UI會發生肉眼可見的變化,那么就需要使用Platform.runLater處理。否則的話不用。