1

Okay, I re-edited this question with a much easier smaller example.

My question is though, I have a StackPane, myStackPane that I am trying to load the Label onto. When the program first runs, the StackPane is empty. When I click on the handleButtonAction button it takes me to another stage so I can enter in the text I want on the label. When that new text is saved, it passes the new settings back to the main controller and updates the text of the label. It then adds the label to the StackPane.

However.... It's not displaying the new label in the stackpane. I know I am getting into the method and the variable is being passed correctly since I can System.out.println everything and it's all appropriate. But why will it not add it to the StackPane?

Thanks everyone!

Problems.java

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

public class Problems extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));

        Scene scene = new Scene(root);

        stage.setScene(scene);
        stage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

}

FXMLDocumentController

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class FXMLDocumentController implements Initializable {

    @FXML
    private Button button;
    @FXML
    private StackPane myStackPane;

    private Label label = new Label("Text 1");

    @FXML
    private void handleButtonAction(ActionEvent event) {
        FXMLLoader secondLoader = new FXMLLoader();

        secondLoader.setLocation(getClass().getResource("FXMLSecond.fxml"));

        try {
            secondLoader.load();
        } catch (IOException e) {
        }

        FXMLSecondController secondController = secondLoader.getController();

        secondController.setFieldText(label.getText());

        Parent p = secondLoader.getRoot();
        Stage stage = new Stage();
        stage.setScene(new Scene(p));
        stage.showAndWait();
    }

    public void putLabelOnStackPane(String value) {
        label.setText(value);

        myStackPane.getChildren().add(label);
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO
    }    

}

FXMLSecondController

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.stage.Stage;

public class FXMLSecondController implements Initializable {

    @FXML
    private Button saveText;
    @FXML
    private TextField textField;

    /**
     * Initializes the controller class.
     */


    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO
    }    

    @FXML
    private void saveTextBtnPressed(ActionEvent event) {
        FXMLLoader firstLoader = new FXMLLoader();

        firstLoader.setLocation(getClass().getResource("FXMLDocument.fxml"));

        try {
            firstLoader.load();
        } catch (IOException e) {
        }

        FXMLDocumentController firstController = firstLoader.getController();

        firstController.putLabelOnStackPane(textField.getText());

        Stage stage = (Stage) saveText.getScene().getWindow();
        stage.close();
    }

    public void setFieldText(String value) {
        textField.setText(value);
    }

}

FXMLDocument

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.StackPane?>

<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="problems.FXMLDocumentController">
    <children>
        <Button fx:id="button" layoutX="128.0" layoutY="14.0" onAction="#handleButtonAction" text="Click Me!" />
      <StackPane fx:id="myStackPane" layoutX="61.0" layoutY="45.0" prefHeight="150.0" prefWidth="200.0" />
    </children>
</AnchorPane>

FXMLSecond

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>


<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/10.0.1" fx:controller="problems.FXMLSecondController">
   <children>
      <Button fx:id="saveText" layoutX="274.0" layoutY="106.0" mnemonicParsing="false" onAction="#saveTextBtnPressed" text="Button" />
      <TextField fx:id="textField" layoutX="226.0" layoutY="175.0" />
   </children>
</AnchorPane>
c0der
  • 18,467
  • 6
  • 33
  • 65
Kfly
  • 27
  • 8

1 Answers1

1

The main issue is that by

FXMLLoader firstLoader = new FXMLLoader();
firstLoader.setLocation(getClass().getResource("FXMLDocument.fxml"));

you actually construct a new FXMLLoader rather then getting a reference to the open one.
You could get a reference to the open FXMLLoader by, for example, using static members (see here) but it would be better to use a slightly different approach:

FXMLDocumentController.java

public class FXMLDocumentController implements Initializable {

    @FXML
    private Button button;
    @FXML
    private StackPane myStackPane;

    private Label label = new Label("Text 1");

    @FXML
    private void handleButtonAction(ActionEvent event) {

        FXMLLoader secondLoader = new FXMLLoader();
        secondLoader.setLocation(getClass().getResource("FXMLSecond.fxml"));

        try {
            secondLoader.load();
        } catch (IOException e) {e.printStackTrace();  }

        FXMLSecondController secondController = secondLoader.getController();
        //secondController.setFieldText(label.getText());
        secondController.setTextProperty(label.textProperty());

        Parent p = secondLoader.getRoot();
        Stage stage = new Stage();
        stage.setScene(new Scene(p));
        stage.showAndWait();
        myStackPane.getChildren().add(label);
    }

    /*
    public void putLabelOnStackPane(String value) {
        label.setText(value);

        myStackPane.getChildren().add(label);
    }*/

    @Override
    public void initialize(URL url, ResourceBundle rb) { //no need to implement Initializable 
                                                         //if initialize not used 
    }    
}

FXMLSecondController.java

public class FXMLSecondController implements Initializable {

    @FXML
    private Button saveText;
    @FXML
    private TextField textField;

    private StringProperty labelStringProperty;

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        textField.setEditable(true);
    }    

    @FXML
    private void saveTextBtnPressed(ActionEvent event) {

        /** By doing so you actually construct a new FXMLDocument
        FXMLLoader firstLoader = new FXMLLoader();
        firstLoader.setLocation(getClass().getResource("FXMLDocument.fxml"));

        try {
            firstLoader.load();
        } catch (IOException e) {
        }

        FXMLDocumentController firstController = firstLoader.getController();
        firstController.putLabelOnStackPane(textField.getText());
        */
        labelStringProperty.set(textField.getText());
        Stage stage = (Stage) saveText.getScene().getWindow();
        stage.close();
    }

    /*
    public void setFieldText(String value) {
        textField.setText(value);
    }*/

    public void setTextProperty(StringProperty labelStringProperty) {
        this.labelStringProperty = labelStringProperty;
        textField.setText(labelStringProperty.get());
    }
}

Also consider using Dialog for input.

EDIT To have FXMLSecondController add a label to FXMLDocoment change FXMLDocumentController to pass the needed references to FXMLSecondController:

public class FXMLDocumentController {

    @FXML
    private Button button;
    @FXML
    private StackPane myStackPane;

    private Label label = new Label("Text 1");

    @FXML
    private void handleButtonAction(ActionEvent event) {

        FXMLLoader secondLoader = new FXMLLoader();
        secondLoader.setLocation(getClass().getResource("FXMLSecond.fxml"));

        try {
            secondLoader.load();
        } catch (IOException e) {e.printStackTrace();  }

        FXMLSecondController secondController = secondLoader.getController();
        secondController.setRefrences(myStackPane.getChildren(), label);

        Parent p = secondLoader.getRoot();
        Stage stage = new Stage();
        stage.setScene(new Scene(p));
        stage.showAndWait();
    } 
}

And have FXMLSecondController use those references:

public class FXMLSecondController {

    @FXML
    private Button saveText;
    @FXML
    private TextField textField;

    private ObservableList<Node> children;
    private Label label;

    @FXML
    private void saveTextBtnPressed(ActionEvent event) {

        label.setText(textField.getText());
        children.add(label);
        Stage stage = (Stage) saveText.getScene().getWindow();
        stage.close();
    }

    public void setRefrences(ObservableList<Node> children, Label label) {      
        this.children = children;
        this.label = label;
        textField.setText(label.getText());
    }
}
c0der
  • 18,467
  • 6
  • 33
  • 65
  • Thank you very much for the response. Your example does not add the label to the `StackPane` though. Which is what my problem was to begin with. I understand now that creating a new `FXML Loader` was creating a whole new FXML and not applying the changes to the currently open one. So, can I get a reference to the already open `StackPane` and add the label from the `FXMLsecondcontroller`? Would it be appropriate to use a static reference to the `StackPane`? – Kfly Nov 11 '18 at 16:20
  • The "problem was to begin with" was not setting a label, but getting the right reference. I am glad my answer clarified it. You can get a static reference but it would be better to path a reference of the stackpane children by `secondController.setChidren(myStackPane.getChildren());` instead of`secondController.setTextProperty(label.textProperty());` . If needed I can add this option to the answer later. – c0der Nov 11 '18 at 16:34
  • Sorry, you are correct. My problem was getting the correct reference. I am still a little confused by "path a reference of the stackpane children..." So if you could add/update when you get a chance that would be great. Maybe it will make more sense when I see your code. I just am lost on how to reference the existing StackPane without creating a new controller. I was looking at [This](https://stackoverflow.com/questions/42817377/javafx-updating-controller-property-from-another-controller) but I'm not sure this is correct either, and I haven't had a chance to try it with my code yet. – Kfly Nov 11 '18 at 17:35
  • Updated my answer. Hope it helps. – c0der Nov 11 '18 at 18:11
  • I'm starting to follow what you're doing here... However, I'm getting a `NullPointerException` on this `secondController.setRefrences(myStackPane.getChildren(), label);` line. I'm assuming it's because the StackPane is empty, and has no children? EDIT: But, I added children and still get the nullPointer. – Kfly Nov 11 '18 at 19:17
  • I GOT IT WORKED OUT! Using the information you provided and a couple hours on google. Plus [THIS](https://code.makery.ch/library/javafx-tutorial/part3/) link. Thank you very much for your help. I would have definitely been stuck without your explanations and patients with me. – Kfly Nov 11 '18 at 20:29
  • I am glad it helped. `myStackPane.getChildren()` sholud not return null when StackPane is empty. There must have been other reason for it. When you post more questions, leave me a message here and I'll try to help. – c0der Nov 12 '18 at 04:29