Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaFX - How to use a method in a controller from another controller?

Working with SceneBuilder. I have 2 stages, each one with a controller:
stage1Controller,
stage2Controller.
Stage1Controller :

public class Stage1Controller {
    @FXML
    private MenuItem translate;
    @FXML
    private Menu file;
    @FXML
    private Menu edit;
    @FXML
    private Menu help;


    @FXML 
    private void handleTranslate (ActionEvent event){
        translateFirstStage();
        //HOW TO ACCESS THE stage2Controller setLabel()??
    }

    private void translateFirstStage(){
        file.setText("Fichier");
        edit.setText("Modifier");
        help.setText("Aide");
    }
}

Stage2Controller:

public class Stage2Controller {
    @FXML
    private Label lb;


    private void setLabel(String string){
        lb.setText("string");
    }
}

Here is how both fxml files are loaded in Main.java class using 2 methods
(called in Start(Stage primaryStage) method):

public void firstStage() {
        try {
            // Load root layout from fxml file.
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(Main.class.getResource("view/stage1.fxml"));
            rootLayout = (BorderPane) loader.load();

            // Show the scene containing the root layout.
            Scene scene = new Scene(rootLayout);
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void secondStage() {

        try {
            // Load root layout from fxml file.
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(Main.class.getResource("view/stage2.fxml"));
            XD = (AnchorPane) loader.load();

            // Show the scene containing the root layout.
            Scene scene = new Scene(XD);
            Stage stage = new Stage();
            stage.setScene(scene);
            stage.show();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  • The handleTranslate(ActionEvent event) method is used as an OnAction method for the MenuItem translate in the first Stage, it translates the view in both stages.

How Can i put setLabel in handleTranslate Method ? Thanks

like image 408
Mohamed Benmahdjoub Avatar asked Apr 15 '15 01:04

Mohamed Benmahdjoub


People also ask

Can an FXML file have 2 controllers?

During the loading of your FXML markup, there is only the provision to have one controller specified for your scene graph. You are able to load other FXML markup files and nest controllers, but I don't think that's what you're asking. To my mind, it doesn't matter anyway.

How do I specify a controller in FXML?

It is also possible to assign the controller class directly from the FXML file. In order to do that, you should first open your FXML file and add the following code on the first line of the file right after declarations. Example: Since my controller is inside the package name “view”, my fx: controller = “view.

What does the Init method do in JavaFX?

The init method is called on the launcher thread, not on the JavaFX Application Thread. This means that an application must not construct a Scene or a Stage in the init method. An application may construct other JavaFX objects in the init method.

Which interface should be used with controller class of JavaFX application?

JavaFX controller works based on MVC(Model-View-Controller) JavaFX MVC can be achieved by FXML (EFF-ects eXtended Markup Language). FXML is an XML based language used to develop the graphical user interfaces for JavaFX applications as in the HTML.


1 Answers

The "quick and dirty" way is to give the Stage1Controller a reference to the Stage2Controller:

public class Stage1Controller {

    private final Stage2Controller stage2Controller ;

    public void setStage2Controller(Stage2Controller stage2Controller) {
        this.stage2Controller = stage2Controller ;
    }

    // ...

    @FXML 
    private void handleTranslate (ActionEvent event){
        translateFirstStage();
        stage2Controller.setLabel(...);
    }

    // other code as before ...
}

Now in your main app:

public class MainApp  extends Application {

    private Stage1Controller stage1Controller ;
    private Stage2Controller stage2Controller ;

    @Override
    public void start(Stage primaryStage) {
        firstStage();
        secondStage();

        stage1Controller.setStage2Controller(stage2Controller);

        // ...
    }

    public void firstStage() {
        try {
            // Load root layout from fxml file.
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(Main.class.getResource("view/stage1.fxml"));
            rootLayout = (BorderPane) loader.load();

            stage1Controller = loader.getController();

            // Show the scene containing the root layout.
            Scene scene = new Scene(rootLayout);
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void secondStage() {

        try {
            // Load root layout from fxml file.
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(Main.class.getResource("view/stage2.fxml"));
            XD = (AnchorPane) loader.load();

            stage2Controller = loader.getController();

            // Show the scene containing the root layout.
            Scene scene = new Scene(XD);
            Stage stage = new Stage();
            stage.setScene(scene);
            stage.show();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // ...
}

A more robust approach to this, though, is to let both controllers access a shared model class, storing the data. If you represent the data using JavaFX observable properties, the controllers can listen for changes on the properties they care about. For example:

public class Model {

    private final StringProperty text = new SimpleStringProperty("Initial text...");

    public StringProperty textProperty() {
        return text ;
    }

    public final void setText(String text) {
        textProperty().set(text);
    }

    public final String getText() {
        return textProperty().get();
    }

    // other properties as needed...
}

Now your controllers will look like this:

public class Stage1Controller {

    private Model model ;

    public void setModel(Model model) {
        this.model = model ;
    }

    @FXML 
    private void handleTranslate (ActionEvent event){
        translateFirstStage();

        model.setText(...); // value will appear in stage2 controller's label!
    }

    // ...
}

and

public class Stage2Controller {

    @FXML
    private Label lb ;

    private Model model ;

    public void setModel(Model model) {
        lb.textProperty().unbind();
        this.model = model ;
        lb.textProperty().bind(model.textProperty());
    }

    // ...
}

And in this case your main app looks like:

public class MainApp extends Application {

    private final Model = new Model();

    @Override
    public void start(Stage primaryStage) {
        // ...
    }

    public void firstStage() {
        try {
            // Load root layout from fxml file.
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(Main.class.getResource("view/stage1.fxml"));
            rootLayout = (BorderPane) loader.load();

            Stage1Controller controller = loader.getController();
            controller.setModel(model);

            // Show the scene containing the root layout.
            Scene scene = new Scene(rootLayout);
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void secondStage() {

        try {
            // Load root layout from fxml file.
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(Main.class.getResource("view/stage2.fxml"));
            XD = (AnchorPane) loader.load();

            Stage2Controller controller = loader.getController();
            controller.setModel(model);

            // Show the scene containing the root layout.
            Scene scene = new Scene(XD);
            Stage stage = new Stage();
            stage.setScene(scene);
            stage.show();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
like image 186
James_D Avatar answered Nov 15 '22 07:11

James_D