[英]JavaFX: Have background task update label text on FXML window?
我的目標是創建一個javaFX窗口,單擊該窗口將增加單例類的計數器。 后台任務應讀取單例中的值,並將其顯示在同一窗口中。 下面是單例。
Singleton.java:
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return singleton;
}
//=====================================
private int count = 0;
public void increment() {
count++;
System.out.println(count);
}
public int getCount() {
return count;
}
}
為了創建后台線程,我嘗試通過JavaFX.INITIALIZABLE提供的initialize()方法創建任務,但這會產生“ 不在FX應用程序線程上 ”錯誤。 下面是獲取FXML並啟動窗口的主要工具。
main.java:
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
try {
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Hello World");
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Sample.fxml-在這里定義窗口結構。 請注意第一個標簽的fx:id =“ counter” 。
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="199.0" prefWidth="230.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.Controller">
<children>
<AnchorPane layoutX="22.0" layoutY="9.0" prefHeight="182.0" prefWidth="186.0">
<children>
<Button layoutX="14.0" layoutY="76.0" mnemonicParsing="false" onAction="#buttonClicked" text="Increment" />
<Label fx:id="counter" layoutX="131.0" layoutY="81.0" text="0" />
<Label layoutX="28.0" layoutY="34.0" text="First JavaFX Project" />
</children>
</AnchorPane>
</children>
</Pane>
Controller.java-最后是控制器。 初始化函數創建一個新線程來運行獲取計數器值所需的任務,但無法編輯原始窗口。
public class Controller implements Initializable {
// Links to Singleton classes
private Singleton sin = Singleton.getInstance();
// Links to FXML elements
@FXML
private Label counter;
public void buttonClicked() {
System.out.print("Click");
sin.increment();
}
@Override
public void initialize(URL arg0, ResourceBundle arg1) {
MyTask myTask = new MyTask();
Thread myTaskThread = new Thread(myTask);
myTaskThread.start();
}
class MyTask extends Task<Void>{
@Override
protected Void call() throws Exception {
while(true) {
int count = sin.getCount();
counter.setText(Integer.toString(count));
}
}
}
}
如何獲得此線程來定期更新正在運行的應用程序上的FXML元素?
我相信您嘗試更新文本的行必須在此代碼內使用
Platform.runLater(() -> {insert your code here});
這是您的類MyTask在更新文本值時的外觀:
class MyTask extends Task<Void>{
@Override
protected Void call() throws Exception {
while(true) {
int count = sin.getCount();
Platform.runLater(() -> {
counter.setText(Integer.toString(count));
});
}
}
}
嘗試更新用戶界面上的任何內容時,您必須位於應用程序線程上。 上面的代碼告訴程序在應用程序線程上執行代碼。
您的用例不需要后台線程即可完成,您只需要使用javafx雙向綁定和StringProperty
public class Controller implements Initializable {
// Links to Singleton classes
private Singleton sin = Singleton.getInstance();
// Links to FXML elements
@FXML
private Label counter;
private StringProperty singletonCounter;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
singletonCounter = new SimpleStringProperty();
singletonCounter.set(sin.getCount() + "");
counter.textProperty().bind(singletonCounter);
}
public void buttonClicked() {
sin.increment();
singletonCounter.setValue(sin.getCount() + "");
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.