2

Something strange is happening.. Untill 10 minutes ago I had no problem with this code. But now I have a problem updating JUST my VBOX from an external thread.

These are my three classes:

Controller Class:

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

Main Class:

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

 }

Connection THREAD:

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

Debugging the Application Everything works perfectly untill I reach slaveVbox.getChildren().addAll(newNode); Here comes the exception.. After some attempt to solve the problem I figured out that if I create a ButtonBar and I insert it in the slaveVbox from Main (inside start()) it works fine.. So I ve tied to add controller2.create("FIRST", "FIRST", true); in my start() function like this:

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

But obviously my application shows two ButtonBars... One created in the start() function and one created inside the Connection Thread.. How Can I avoid this?? Why I can't directly add item inside my VBox directly from my Connecton thread??

1 Answer 1

3

You cannot update the UI from a thread other than the FX Application Thread. See, for example, the "Threading" section in the Application documentation.

It's not at all clear why you are using a background thread at all here: there doesn't seem to be any long-running code in the method you are calling. In general, if you have long-running code to call, you can call it in a background thread and then update the UI by wrapping UI update in a Platform.runLater(...).

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();
        }
   }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Teorically I simplify my code.. But I have a while loop that read data from a socket.. i will try what you advice.. I ll be there soon

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.