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

后端 未结 1 1134
臣服心动
臣服心动 2020-11-29 09:58

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

相关标签:
1条回答
  • 2020-11-29 10:35

    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();
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题