JavaFX - Как использовать метод в контроллере из другого контроллера?

Работа с конструктором сцен. У меня есть 2 этапа, каждый с контроллером:
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");
    }
}

Контроллер Stage2:

public class Stage2Controller {
    @FXML
    private Label lb;


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

Вот как оба файла fxml загружаются в класс Main.java с использованием двух методов
(вызывается в методе 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();

            // 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();
        }
    }
  • Метод handleTranslate(ActionEvent event) используется как метод OnAction для MenuItem translate на первом этапе, он транслирует представление на обоих этапах.

Как поместить setLabel в метод handleTranslate? Спасибо


person Mohamed Benmahdjoub    schedule 15.04.2015    source источник
comment
Где загружаются файлы fxml, соответствующие соответствующим контроллерам? (Вам нужна ссылка на ваш экземпляр Stage2Controller в вашем Stage1Controller.)   -  person James_D    schedule 15.04.2015
comment
оба файла fxml загружаются в класс mainApp, который отделен от обоих.   -  person Mohamed Benmahdjoub    schedule 15.04.2015
comment
Пожалуйста, отредактируйте свой вопрос, чтобы показать этот код.   -  person James_D    schedule 15.04.2015
comment
Готово, я добавил, как я загрузил 2 файла fxml.   -  person Mohamed Benmahdjoub    schedule 15.04.2015
comment
Ага, спасибо; что помогает. Смотрите ответ.   -  person James_D    schedule 15.04.2015


Ответы (1)


"Быстрый и грязный" способ - дать Stage1Controller ссылку на 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 ...
}

Теперь в вашем основном приложении:

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();
        }
    }

    // ...
}

Однако более надежным подходом к этому является предоставление обоим контроллерам доступа к общему классу модели, хранящему данные. Если вы представляете данные с помощью наблюдаемых свойств JavaFX, контроллеры могут прослушивать изменения свойств, которые им интересны. Например:

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...
}

Теперь ваши контроллеры будут выглядеть так:

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!
    }

    // ...
}

а также

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());
    }

    // ...
}

И в этом случае ваше основное приложение выглядит так:

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();
        }
    }
}
person James_D    schedule 15.04.2015