java.lang.IllegalStateException:不在FX应用程序线程调用函数上

时间:2016-02-13 16:43:52

标签: multithreading exception javafx controller

发生了一些奇怪的事情..直到10分钟前我对此代码没有任何问题。但是现在我在从外部线程更新JUST我的VBOX时遇到了问题。

这是我的三个班级:

控制器类:

public class Controller implements Initializable{
@FXML
private VBox slaveVbox;

private ButtonBar newNode = new ButtonBar();
private Circle c= new Circle();
private Button b= new Button();
private Label lname = new Label();
private Label lIMEI = new Label();
private Label lroot = new Label();

@Override
public void initialize(URL location, ResourceBundle resources) {
}

public void create(String imei, String permission,boolean isOnline) throws IOException{
    if(!alreadyExist(imei)){
    newNode = new ButtonBar();
    b = setButtonSpec(imei + "btnHavefun");
    c = setCircleSpec(imei + "statuOnline", isOnline);
    lname= setLNameSpec(imei + "name");
    lIMEI = setLIMEISpec(imei + "Imei");
    lroot = setLrootSpec(imei + "root", permission);
    newNode.getButtons().addAll(lname,lIMEI,lroot,b,c);
    slaveVbox.getChildren().addAll(newNode);
   }
  }
}

主类:

public class MainApp extends Application {
 FXMLLoader loader2;
 private Stage primaryStage;
 private BorderPane rootLayout;

@Override
public void start(Stage primaryStage) throws IOException {
    this.primaryStage = primaryStage;
    this.primaryStage.setTitle("Thypheon Application");
    initRootLayout();
    Controller controller2 = initDesign();
    Connection con = new Connection(controller2);
    Thread t = new Thread(con);
    t.start();

    primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
           @Override
           public void handle(WindowEvent e) {
              Platform.exit();
              System.exit(0);
           }
        });
}

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

public void initRootLayout(){
    try {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("RootLayout.fxml"));
        rootLayout = (BorderPane) loader.load();
        Scene scene = new Scene(rootLayout);
        primaryStage.setScene(scene);
        primaryStage.show();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

public Controller initDesign(){
    try {
        FXMLLoader loader2= new FXMLLoader(getClass().getResource("Design.fxml"));
        AnchorPane anchor  = (AnchorPane) loader2.load();
        rootLayout.setCenter(anchor);
        Controller controller = loader2.getController();
        return controller;

    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        return null;
    }

}


public Stage getPrimaryStage(){
    return primaryStage;
}

 }

连接线程:

public class Connection implements Runnable {
 String result;
 Controller controller;

   public Connection(Controller controller) {
       this.controller = controller;
   }

@Override
public void run() {
        try {
            controller.create("jhgjhgjh", "dssf", true);
    } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
 }

调试应用程序一切正常,直到我到达slaveVbox.getChildren().addAll(newNode);以下是例外情况.. 在尝试解决问题之后,我发现如果我创建一个ButtonBar并将其从Main(在start()内部插入slaveVbox中,它可以正常工作..所以我在我的开始添加controller2.create("FIRST", "FIRST", true); ()函数如下:

@Override
public void start(Stage primaryStage) throws IOException {
    this.primaryStage = primaryStage;
    this.primaryStage.setTitle("Thypheon Application");
    initRootLayout();
    Controller controller2 = initDesign();
    controller2.create("FIRST", "FIRST", true);
    Connection con = new Connection(controller2);
    Thread t = new Thread(con);
    t.start();

    primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
           @Override
           public void handle(WindowEvent e) {
              Platform.exit();
              System.exit(0);
           }
        });
}

但显然我的应用程序显示了两个ButtonBars ...一个在start()函数中创建,一个在Connection Thread中创建。我怎么能避免这个?为什么我不能直接从我的Connecton线程中直接在我的VBox中添加项目?

1 个答案:

答案 0 :(得分:2)

您无法从FX应用程序线程以外的线程更新UI。例如,请参阅Application documentation中的“线程”部分。

完全不清楚为什么你在这里使用后台线程:在你调用的方法中似乎没有任何长时间运行的代码。通常,如果您有长时间运行的代码来调用,则可以在后台线程中调用它,然后通过在Platform.runLater(...)中包装UI更新来更新UI。

public class Connection implements Runnable {
  String result;
  Controller controller;

   public Connection(Controller controller) {
       this.controller = controller;
   }

   @Override
   public void run() {
        try {
            // execute long-running code here...

            // perform any updates to the UI on the FX Application Thread:
            Platform.runLater(() -> {
                // code that updates UI
            });

            // more long-running code can go here...

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
   }
}