如何从另一个控制器访问 FXML 方法

How to access FXML method from another controller

我在 MenuController.java 中有一个 onExitButtonClick FXML 方法,如何在 GameOverController.java 中访问相同的 FXML 方法?一个退出按钮在Menu场景,一个在Game Over场景。

MenuController.java

@FXML
private void onExitButtonClick() {
    System.out.println("Goodbye " + System.getProperty("user.name"));
    System.exit(0);
}

GameOverController.java

@FXML
private void onExitButtonClick() {
    System.out.println("Goodbye " + System.getProperty("user.name"));
    System.exit(0);
}

有没有办法减少代码的冗余?

具体回答问题标题

How to access FXML method from another controller

不要。

除了以下特定情况外,控制器不需要相互调用方法:

即便如此,这也不是大多数应用程序的最佳实践。

最佳做法是使用共享模型 classes 和使用 mvc 的控制器外部的服务逻辑。控制器逻辑应仅限于管理视图和通过侦听器链接视图模型并绑定到 object 模型。

对于共享 UI 组件,创建自定义小部件 classes 并重用它们。例如,参见 Oracle 教程:

在自定义控件中使用fxml是可选的,但概念与教程类似。您可以用普通 Java 编写您的自定义控件。此外,让它扩展窗格而不是控件通常就足够了,因为那样更容易。

一般情况下,使用mvc

如果你想重构,一个合理的设计是不在控制器中执行应用程序逻辑,而是有一个共享域级服务层,与 UI 和在共享 [= 上工作的控制器分开103=]型号。

有关信息,请参阅:

对于大中型应用程序来说,这是一个不错的模型,例如四个或更多屏幕,但可能会为只有一个或两个屏幕的非常小的应用程序引入不必要的抽象。所以值不值还是要看app。

具体应用关闭案例:应用静态方法

您退出应用程序的特殊情况是一个特殊情况,不适用于大多数其他情况。特别之处在于退出是一个真正的应用程序级函数,并且已经有一个特定的 class 来处理应用程序生命周期。那将是您的 class 子 classes 应用程序。因此,只有处理退出的代码才有意义。

要了解有关应用程序生命周期的更多信息,我强烈建议您 re-read JavaFX Application javadoc。

JVM 中只允许应用程序的一个实例,因此可以使用静态方法从应用程序中的任何位置访问该实例。

因此,有了这些知识,我们可以重构您的调用。在任何控制器或您想要关闭应用程序的任何其他地方,写:

@FXML
private void onExitButtonClick() {
    MyApplication.exit();
}

并在您的应用程序中 class 定义一个静态方法:

public static void exit() {
    System.out.println("Goodbye " + System.getProperty("user.name"));
    Platform.exit();
}

请注意,调用是为了退出平台而不是系统,因为这是 JavaFX 应用程序生命周期中关闭应用程序的推荐方式。如果您想为退出提供一些上下文(例如退出原因消息),您可以将参数传递给退出调用。

这种在应用程序中调用静态函数的方法也可以用于其他共享逻辑。

除了琐碎的小应用程序,我只推荐这种方法用于与应用程序生命周期直接相关的逻辑。

对于大型应用程序中的通用逻辑,建议使用 mvc、具有可绑定属性的共享 object 模型和依赖项注入等技术。

具体应用关闭案例:应用生命周期集成

因为这是处理应用程序生命周期的特殊情况,您可以更紧密地与之集成并完全删除额外的静态方法。如果你这样做,那么你会得到这个代码,只要你想退出就调用 Platform.exit():

@FXML
private void onExitButtonClick() {
    Platform.exit();
}

并且在您的 JavaFX 应用程序中 class 代码:

@Override
public void stop() {
    System.out.println("Goodbye " + System.getProperty("user.name"));
}

之所以可行,是因为 stop() 方法是退出平台时调用的回调。

顺便说一句,这就是为什么您应该调用 Platform.exit 而不是 System.exit。如果直接退出系统,会短路平台关闭逻辑,停止逻辑不会被调用。