s4inz
s4inz

Reputation: 123

JavaFX: Dynamically added VBox does not show up

I'm working on a project that requires a "tabled" representation of VBoxes. My hierarchical layout of the application is GridPane -> VBox (in one of the Cells) -> VBoxes (that display different datasets on top of each other) -> Data. I have two Scenes.

Data is displayed on Scene 1. The user can add data through a form and by clicking a button on Scene 2. Then, the added data should be displayed below the existing data as a VBox within the parent-VBox on Scene 1 again.

Here is the code that will make it clear:

My Scene 1 .fxml file looks the following (Simplified):

<GridPane fx:id="grid" fx:controller="application.Controller">
  [here: ColumnConstraints]
  <children>
    <VBox fx:id="parentBox" GridPane.columnIndex="0" GridPane.rowIndex="1"/>
    <Button fx:id="goToScene2" text="+" onAction="#goToScene2"/> 
  </children>  
</GridPane>

Scene 2 just has a button and a TextField:

<GridPane fx:id="grid" fx:controller="application.AddDataController">
  [here: ColumnConstraints]
  <children>
    <Button fx:id="addData" text="add" onAction="#bAddData"/> 
    <TextField fx:id="data"/>
  </children>  
</GridPane>

My Scene 1 controller (controller) looks like this:

public class Controller implements Initializable  {
  @FXML Button goToScene2;
  @FXML VBox parentBox;

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

  public void addData(String s) {
    Label lbl = new Label(s);
    VBox dataBox = new VBox();
    dataBox.setPadding(new Insets(15, 5, 15, 5));
    dataBox.setSpacing(5);
    dataBox.setMaxHeight(80);
    dataBox.getChildren().add(lbl);
    parentBox.getChildren().add(dataBox);
  }
}

This is designed as it is because the dataBox contains more elements than the label, but that doesn't seem relevant to me in this context.

My Scene 2 controller (addDataController) looks like this:

@FXML Button addData;
@FXML TextField data;

@FXML protected void bAddData(){
  String content = data.getText();    
  FXMLLoader fxmlLoader = new FXMLLoader();
  Pane p = fxmlLoader.load(getClass().getResource("scn1.fxml").openStream());
  Controller cont = (Controller) fxmlLoader.getController();

  cont.addData(content);
}

So, when one clicks on the Add-Data-Button in Scene 2, the triggered method passes the entered data to the Controller of Scene 1. This is because the new data should be displayed in Scene 1 now.

I feel like the logic does not work (edited here), because when I ask for

System.out.println(parentBox.getChildren().size();

before and after the data was added, it always has one single Child, even though it should have one more...

If I artificially fill a String-Array and move everything from addData to(String s) to Initialize(...), it does work and the data shows up as VBoxes in the parent-VBox.

I didn't post the main class, because loading Controllers and Scene change is not an issue.

Thank you all very very much for your help! :)

Upvotes: 0

Views: 1880

Answers (1)

s4inz
s4inz

Reputation: 123

Just to provide more detailed information, together with an idea, that I don't know how to implement.

This is my main class:

@Override
public void start(Stage primaryStage) {
  currentStage = primaryStage;
  Parent root = FXMLLoader.load(getClass().getResource("Scene1.fxml"));
  scene1 = new Scene(root);
}

Could I load the controller at this point and make a getter that passes the Controller? So I'd only have one single instance of it throughout the program.

I tried inserting:

FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.load(getClass().getResource("Scene1.fxml").openStream());
Controller controller = (Controller) fxmlLoader.getController();

after the

Parent root ...

line. But that's loading the .xml file twice. How can I nicely connect both parts?

Thanks so much for you patience!

EDIT::::::::: The following code worked for me:

@Override
public void start(Stage primaryStage) {
  currentStage = primaryStage;
  FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Scene1.fxml"));
  Parent root =(Parent) fxmlLoader.load();
  controller = (Controller) fxmlLoader.getController();
}

Now, I can ask the main class for controller and it always passes that single instance.

Thank you for pointing me to the right direction! :)

Upvotes: 0

Related Questions