如何获取对另一个控制器的引用-JavaFX

如何获取对另一个控制器的引用-JavaFX,javafx,Javafx,假设我有3个视图和3个控制器: LogInController,LogInView MainMenuController,MainMenuView 内部医疗中心控制器患者列表,内部医疗中心视图患者列表 单击一个InternalMedicineButonClicked方法将我的场景更改为另一个场景(带有一些其他内容),但在这个新场景中,我希望有一个按钮,允许我返回主菜单(goBacktoMainMenuButtonClicked()方法)。我的问题来了。我如何才能获得对MainMenuContro

假设我有3个视图和3个控制器:
LogInController
LogInView

MainMenuController
MainMenuView

内部医疗中心控制器患者列表
内部医疗中心视图患者列表

单击一个
InternalMedicineButonClicked
方法将我的场景更改为另一个场景(带有一些其他内容),但在这个新场景中,我希望有一个按钮,允许我返回主菜单(
goBacktoMainMenuButtonClicked()
方法)。我的问题来了。我如何才能获得对MainMenuController(与在LogInController中创建的fxml文件相对应的文件)的引用,以填充
setController()
方法

public class LogInController {

MainMenuController mainMenuController =  new MainMenuController();
@FXML
private JFXTextField logInTextField;
@FXML
private JFXButton logInButton;
@FXML
private JFXPasswordField passwordTextField;

@FXML
void logInButtonClicked(ActionEvent event) throws IOException {
    LogInDAO logInDAO = new LogInDAO();
    if(logInDAO.checkIfLoginAndPasswordIsCorrect(logInTextField.getText(),passwordTextField.getText()))
    {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/MainMenu.fxml"));
        Window window = logInButton.getScene().getWindow();
        Stage stage = (Stage) window;
        loader.setController(mainMenuController); // here i'm passing original controller corresponding with fmxl
        stage.setScene(new Scene(loader.load()));
    }
    else
    {
             (...)
    }
}

}
MainMenuController类:

public class MainMenuController {
ContentOfPatientTableView patientTableViewModel = new ContentOfPatientTableView();
(..)
  @FXML
    void internalMedicineButtonClicked(ActionEvent event) throws IOException {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/ListOfPatientsInternalMedicineView.fxml"));
        Button button = (Button) event.getSource();
        Scene scene = button.getScene();
        Stage stage = (Stage) scene.getWindow();
        loader.setController(new ListOfPatientsInternalMedicineController(patientTableViewModel));
        stage.setScene(new Scene(loader.load()));

    }
以及InternalMedicineController类的患者列表

public class ListOfPatientsInternalMedicineController {
    IPatientDAO patientDAO = new PatientDAO();
    ContentOfPatientTableView patientTableViewModel;

    public ListOfPatientsInternalMedicineController(ContentOfPatientTableView content) {
        patientTableViewModel=content;
    }
    @FXML
    public void goBacktoMainMenuButtonClicked(ActionEvent event)
    {
        FXMLLoader loader = new FXMLLoader(MainMenuController.class.getResource("/fxml/MainMenuView.fxml");
        loader.setController(?????????); // Here if I will pass new MainController() i will create new instance, not this which is corresponding with fxml file. How am I able to refer to instance MainController created in LogInController ?
    }
}

考虑使用另一个模型来表示当前视图。您可以通过以下方式实现这一点:

public class ViewState {

    private final ContentOfPatientTableView patientTableViewModel ;

    private final ReadOnlyObjectWrapper<Parent> currentView = new ReadOnlyObjectWrapper<>();

    private Parent logInView ;
    private Parent mainMenuView ;
    private Parent listOfPatientsMainMedicineView ;

    public ViewState(ContentOfPatientTableView patientTableViewModel) {
        this.patientTableViewModel = patientTableViewModel ;
    }

    public ReadOnlyObjectProperty<Parent> currentViewProperty() {
        return currentView.getReadOnlyProperty();
    }

    public void showLogIn() {
        if (logInView == null) {
            try {
                FXMLLoader loader = new FXMLLoader("/fxml/LogIn.fxml");
                loader.setController(new LogInController(this));
                logInView = loader.load();
            } catch (IOException exc) {
                // fatal...
                throw new UncheckedIOException(exc);
            }
        }
        currentView.set(logInView);
    }

    public void showMainMenu() {
        // similarly...
    }

    public void showListOfPatientsMainMedicineView() {
        // ...
    }
}
同样地

public class MainMenuController {

    private final ViewState viewState ;

    public MainMenuController(ViewState viewState) {
        this.viewState = viewState ;
    }

    @FXML
    void internalMedicineButtonClicked(ActionEvent event) throws IOException {
        viewState.showListOfPatientsMainMedicineView();
    }
}
对于另一个控制器也是如此

请注意,您正在
ViewState
中实例化每个控制器,因此只需让该类访问它可能需要的每个其他模型

最后,你可以用

public class MyApp extends Application {

    @Override
    public void start(Stage primaryStage) {
        ViewState viewState = new ViewState(/* pass models here...*/);
        viewState.showLogIn();
        Scene scene = new Scene(viewState.currentViewProperty().get());
        scene.rootProperty().bind(viewState.currentViewProperty());
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

要执行此操作,您必须将
MainMenuController
的实例传递到
患者列表sinternalmedicinecontroller
类。当再次加载FXML时,您可能不希望重用控制器类的实例,因此您可能并不真正希望重新加载FXML。如果主控制器保留对其根元素的引用,则可以使用一个方法将该根元素设置为场景的根元素。将对主控制器的引用传递给第三个控制器,并在需要返回时调用该方法。另一种(可能更好?)方法是使用另一个模型类,该类具有类似于
ObjectProperty currentView
的特性。与您的所有控制器共享该模型(您已经演示了如何使用现有模型执行此操作)。您可以观察该值,并在其更改时将该视图显示为场景的根;然后,控制器只需更改属性即可切换场景。同样,您可能希望加载每个FXML一次。是的,我确实希望加载每个FXML一次,但我仍然不明白如何保存创建的每个FXML加载程序!此ObjectProperty一次只能保存一个场景。我知道如何传递模型等。但我不知道您对该模型应如何工作的想法。我在回答中简述了该想法非常感谢!现在这对我来说是有意义的me@Michael213伟大的它可能需要一些“调整”来获得您想要的方式(例如,您可能只是在“视图状态”中实例化所有其他模型,或者相反,您甚至可以将所有
ViewState
代码移动到
应用程序
类)。但它应该给你这个想法的要点。
public class MyApp extends Application {

    @Override
    public void start(Stage primaryStage) {
        ViewState viewState = new ViewState(/* pass models here...*/);
        viewState.showLogIn();
        Scene scene = new Scene(viewState.currentViewProperty().get());
        scene.rootProperty().bind(viewState.currentViewProperty());
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}