Matteo
Matteo

Reputation: 337

javaFX - how to use function or object of a controller from another controller

I have seen a lot of question similar to mine, but I didn't figure it out how to solve my problem, so there is my code:

I have a simple main:

MainClassFXGui.java

public class MainClassFXGui extends Application {

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

        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.setTitle("Assicurazione");
        stage.show();
    }

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

and three fxml files, one of them that contains the other two, by the tag

<fx:include source="MyTab1.fxml" />

MyProgramMainGuiTab.fxml

...
<TabPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="5000.0" prefWidth="5000.0" tabClosingPolicy="UNAVAILABLE">
          <tabs>
              <Tab closable="false" text="MyTab1">
                   <content>
    <fx:include source="MyTab1.fxml" />
                   </content>
              </Tab>
              <Tab closable="false" text="MyTab2">
                   <content>
    <fx:include source="MyTab2.fxml" />
                   </content>
              </Tab>
          </tabs>
    </TabPane>
...

and three controller:

MyProgramMainGuiTabController.java

....
@FXML
private Label LeftSt;
/**
 * Initializes the controller class.
 */
@Override
public void initialize(URL url, ResourceBundle rb) {
    LeftSt.setText("");
}    

public void setLeftSt(String st){
    LeftSt.setText(st);
}
...

MyTab1Controller.java

@FXML
private void handleButtonAction(ActionEvent event) {
    System.out.println("You clicked me!");
    setLeftSt("Can I change the label of the MyProgramMainGuiTabController?");
}

I tried in this way:

MyTab1Controller.java

private MyProgramMainGuiTabController controller;

@FXML
private void handleButtonAction(ActionEvent event) {
        System.out.println("You clicked me!");
        controller.setLeftSt("Can I change the label of the MyProgramMainGuiTabController?");
}

@Override
public void initialize(URL url, ResourceBundle rb) {
    FXMLLoader fxmlLoader = new
    FXMLLoader(getClass().getResource("MyProgramMainGuiTab.fxml"));
    try {
         fxmlLoader.load();            
    } catch (IOException exception) {
         throw new RuntimeException(exception);
    }
    controller = (MyProgramMainGuiTabController)fxmlLoader.getController();
}

But I have a null pointer exception or if I move the code for the instanzialization of the object 'controller' in the handleButtonAction function, I don't have any error, but the label does not change.

Maybe I can create a static Scene and a static Stage in the MainClassFXGui.java? but then I don't know how I could use them...

MainClassFXGui.java

public class MainClassFXGui extends Application {
    static private Scene scene;
    static private Stage stage;

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

        this.scene = new Scene(root);
        stage.setScene(scene);
        stage.setTitle("Assicurazione");
        stage.show();
        this.stage = stage;
    }
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

    public static Scene getScene(){
        return AssicurazioneFXGui.scene;
    }

    public static Stage getStage(){
        return AssicurazioneFXGui.stage;
    }

}

can I do something with getScene() or getStage()? any idea or suggest?

thanks to everyone

Upvotes: 2

Views: 912

Answers (2)

James_D
James_D

Reputation: 209714

Define a StringProperty in MyTab1Controller, with the usual methods:

public class MyTab1Controller {

    private final StringProperty leftSt = new SimpleStringProperty();

    public StringProperty leftStProperty() { 
        return leftSt ;
    }

    public final String getLeftSt() {
        return leftStProperty().get();
    }

    public final void setLeftSt(String leftSt) {
        leftStProperty().set(leftSt);
    }

    // ...

    @FXML
    public void handleButtonAction() {
        setLeftSt(...);
    }

    // ...
}

Now assign an fx:id attribute to the fx:include tag:

<Tab closable="false" text="MyTab1">
    <content>
        <fx:include fx:id="myTab1" source="MyTab1.fxml" />
    </content>
</Tab>

This means you can inject the controller for MyTab1.fxml into the controller for the FXML where it is included (MyProgramMainGuiTabController):

public class MyProgramMainGuiTabController {

    @FXML
    private MyTab1Controller myTab1Controller ;

}

and then you can just observe the property and update the label when it changes:

public class MyProgramMainGuiTabController {

    @FXML
    private MyTab1Controller myTab1Controller ;

    @FXML
    private Label leftSt;

    public void initialize() {
        leftSt.setText("");
        myTab1Controller.leftStProperty().addListener((obs, oldValue, newValue) -> 
            leftSt.setText(newValue));
    }    
}

Note the rule here is that the field name for the controller is the value of the fx:id attribute with the word "Controller" appended: myTab1 in the fx:id resolves to myTab1Controller for the field where the controller is injected. See NestedControllers for more information.

Upvotes: 1

Matteo
Matteo

Reputation: 337

At the moment I have solved in this way. If anyway someone has a better solution, please write. Also because this does not solve the problem if I need to execute a function.. thanks

MyProgramMainGuiTabController.fxml

...
@FXML
private Label LeftSt;
/**
 * Initializes the controller class.
 */
@Override
public void initialize(URL url, ResourceBundle rb) {
    LeftSt.setText("");
}  
...

MyTab1Controller.fxml

@FXML
private Button myObject;

private Scene scene;
private Label lblDataLeft;

@FXML
private void handleButtonAction(ActionEvent event) {
        System.out.println("You clicked me!");
        setLeftSt("this works!");
}

public void setLeftSt(String st){
    if(this.scene == null)
        this.scene = myObject.getScene();
    if(this.lblDataLeft==null)
        this.lblDataLeft = (Label) scene.lookup("#LeftSt");
    if (this.lblDataLeft!=null) 
        this.lblDataLeft.setText(st); 
}

Upvotes: 0

Related Questions