2016-02-13 51 views
1

发生了一些奇怪的事情。直到10分钟前,我对这段代码没有任何问题。但现在我有一个问题,从外部线程更新我的VBOX。java.lang.IllegalStateException:不在FX应用程序线程调用函数

这些都是我的三类:

控制器类:

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(); 
     } 
} 

调试应用程序Everyt兴作品完美,直到我达到slaveVbox.getChildren().addAll(newNode);这里来的例外.. 经过一些尝试解决这个问题后,我想出了如果我创建一个ButtonBar,并将它插入从主(从start())slaveVbox它工作正常..所以,我已经绑在我的start()函数中添加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()函数创建一个和一个连接线程内创建..我如何避免这种情况?为什么我无法直接从我的Connecton线程直接在VBox中添加项目?

回答

2

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

这完全不清楚你为什么在这里使用后台线程:在你调用的方法中似乎没有任何长时间运行的代码。通常,如果您有长时间运行的代码进行调用,则可以在后台线程中调用该代码,然后通过将UI更新封装在Platform.runLater(...)中来更新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(); 
     } 
    } 
} 
+0

从头到尾我简化了我的代码..但是我有一个从套接字读取数据的while循环..我会尝试你的建议..我会很快到那里 –

相关问题