JavaFX中的线程:不在FX应用程序线程上

3
我希望学习如何在JavaFX中使用线程。例如,有两个进程,每100毫秒更改标签上的文本,并且每100毫秒更新屏幕上的信息。
但是,在这种情况下它不起作用。IDEA会写:
“Exception in thread "Thread-4" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-4”
我已经阅读了许多有同样问题的示例,但他们的任何解决方案都没有起作用。
我应该怎么做?
谢谢。
sample.fxml
...
<Button fx:id="startBut" layoutX="100.0" layoutY="50.0" mnemonicParsing="false" onAction="#testingOfThread" prefHeight="25.0" prefWidth="65.0" text="Export" />
<Label fx:id="firstStatus" layoutX="100.0" layoutY="100" text="Status" />
<Label fx:id="secondStatus" layoutX="100.0" layoutY="150" text="Status" />
...

Main.java

package sample;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
        primaryStage.setTitle("Sample");
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }

    //Take control to Controller
    public void initializeController(){
        FXMLLoader loader = new FXMLLoader();
        Controller controller = loader.getController();
        controller.setMain(this);
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Controller.java

package sample;

import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.scene.control.*;

public class Controller {

    @FXML
    private Label firstStatus;

    @FXML
    private Label secondStatus;

    @FXML
    public Button startBut;


    //Link to MainApp
    private Main Main;

    //Constructor
    public Controller(){
    }


    //Link for himself
    public void setMain(Main main){
        this.Main = main;
    }

    @FXML
    private void testingOfThread(){

        Task<Void> task = new Task<Void>() {
            @Override public Void call() {
                for (int i = 0; i < 100; i++) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        Thread.interrupted();
                        break;
                    }
                    System.out.println(i + 1);
                    firstStatus.setText(i+"");
                }
                return null;
            }
        };

        Thread th = new Thread(task);
        th.setDaemon(true);
        th.start();


        Task<Void> task2 = new Task<Void>() {
            @Override public Void call() {
                for (int i = 0; i < 100; i++) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        Thread.interrupted();
                        break;
                    }
                    System.out.println(i + 1);
                    secondStatus.setText(i+"");
                }
                return null;
            }
        };

        Thread th2 = new Thread(task2);
        th2.start();

    }
}

4
除了应用程序线程以外的线程不要更新GUI。你需要使用Platform.runLater。或者,由于您已经在使用任务,可以通过使用updateMessage更新message属性而不是text属性,并将text属性绑定到message属性:在启动线程之前,调用方法call:/* firstStatus.setText(i+"");*/ updateMessage(Integer.toString(i));``firstStatus.textProperty().bind(task.messageProperty()); - fabian
谢谢你,Fabian!一切正常。 - Kamil Timraleev
1个回答

6

查找在应用程序线程之外的线程更新GUI的代码,然后将它们放入runLater()中。

Platform.runLater(new Runnable() {
    @Override
    public void run() {
        //update application thread
    }
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接