java - 如何使用相同的模型对象初始化 JavaFX Controller ?

标签 java dependency-injection controller javafx fxml

场景

我正在创建一个 GUI,其中多个 View 引用同一个模型对象。

我的习惯

在 Swing 中,如果我希望所有 View 都引用同一个模型,我会将模型传递给构造函数。

我目前在做什么

在 JavaFX 中,在每个 View / Controller 加载后,我通过在 View / Controller (菜单栏、拆分 Pane 、选项卡等)中使用 setter 方法来传递模型。我觉得这非常俗气和麻烦。此外,我发现它不起作用,因为在某些情况下,我需要模型在某些 Controller 小部件初始化之前已经存在于 Controller 中。

乏善可陈的替代品

(注意:我指的是这些 stackoverflow 问题:

  • Javafx 2.0 How-to Application.getParameters() in a Controller.java file
  • Passing Parameters JavaFX FXML
  • Multiple FXML with Controllers, share object
  • Passing parameters to a controller when loading an FXML )

  • 依赖注入(inject)

    • 我看过这个网站,http://www.zenjava.com/2011/10/23/javafx-2-0-fxml-and-spring/ ,并且我对 google Guice 进行了一些研究,但我没有看到一种简单地为每个 JavaFX View / Controller 提供相同模型对象的方法。似乎注入(inject)会为每个 View / Controller 注入(inject)不同的模型。
  • 将模型对象保存为公共(public)静态变量

    • 这是一个选项,但目前我不喜欢拥有如此开放和可用的公共(public)静态模型的想法。显然,我可以将其设为私有(private)静态变量并拥有 getter 和 setter,但我也不太喜欢这个想法。
  • 将参数从调用者传递给 Controller ​​

    • 我希望每个 Controller 在其构造函数中加载自己,并且我希望每个自定义 Controller 自动注入(inject)其父 Controller 。例如,卡片概览选项卡的加载方式如下:

      public CardOverviewTab() {
          FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("card_overview_tab.fxml"));
          fxmlLoader.setRoot(content);
          fxmlLoader.setController(this);
      
          try {
              fxmlLoader.load();
          } catch (Exception e) {
              e.printStackTrace();
          }
      }
      
    • SingleGameSetup Controller 将卡片概览选项卡自动注入(inject)到变量中:

      public class SingleGameSetupController extends AnchorPane {
      
          @FXML private CardOverviewTab cardOverviewTab;
      
          // Rest of the class
      }
      
    • 包含卡片概览选项卡的 fxml 部分如下所示:

      <CardOverviewTab fx:id="cardOverviewTab" />
      
    • 这样我就不用担心手动加载 Controller 了,但是我还是有设置模型的问题。

  • 在 FXMLLoader 上设置 Controller

    • 这个选项和我习惯的差不多,将模型作为参数传入构造函数,但是还是存在使用FXMLLoader手动加载 Controller 的问题。
  • 事件总线

    • 我没有对此进行过多的阅读,但从我阅读的内容来看,事件总线似乎已不活动且已过时。
  • 单例

    • 这类似于 Controller 可以检索模型对象的公共(public)静态引用,但我再次寻找更好的解决方案。另外,我不想要单例模型。

我在寻找什么

有没有办法以不那么麻烦的方式传递模型对象?我正在寻找一种像将模型传递给构造函数一样简单的方法,但我不想通过 FXMLLoader 手动加载 Controller ,或者在加载 Controller 后设置模型。也许有一个类来检索模型是最好的选择,但我只是在问,以防万一有更好的方法。

最佳答案

更新

除了afterburner.fx,还可以查看Gluon Ignite :

Gluon Ignite allows developers to use popular dependency injection frameworks in their JavaFX applications, including inside their FXML controllers. Gluon Ignite creates a common abstraction over several popular dependency injection frameworks (currently Guice, Spring, and Dagger, but we plan at add more as the demand becomes obvious). With full support of JSR-330 Gluon Ignite makes using dependency injection in JavaFX applications trivial.

将模型对象注入(inject) Controller 也是通过@Inject,类似于afterburner.fx。

建议的方法

由于您似乎正在寻找依赖注入(inject)框架,我认为您最好的选择是使用 afterburner.fx framework .

afterburner.fx 提供了一种使用标准 Java @Inject 将模型对象注入(inject) JavaFX Controller 的方法。注解。

替代依赖注入(inject)系统

Spring 庞大而复杂,除非您的应用程序需要很多其他功能,否则由于其复杂性,不应考虑使用它。

Guice 比 Spring 简单得多,如果您需要一个具有众多特性(例如提供程序类)的依赖注入(inject)框架,那么它是一个合理的选择。但从它的声音来看,您不需要 Guice 提供的所有功能,因为您只想要一种在应用程序中传递对象的单例实例而不显式查找它们的方法。

所以,试试 afterburner.fx 看看它是否符合您的需求。

afterburner.fx 示例代码

这是使用 afterburner.fx 将模型实例(NotesStore)注入(inject) Controller 的示例。样本直接复制自afterburner.fx documentation .

import com.airhacks.afterburner.views.FXMLView;

public class NoteListView extends FXMLView {
    //usually nothing to do, FXML and CSS are automatically
    //loaded and instantiated
}

public class AirpadPresenter implements Initializable {    
    @Inject // injected by afterburner, zero configuration required
    NotesStore store;

    @FXML // injected by FXML
    AnchorPane noteList;

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        //view constructed from FXML
        NoteListView noteListView = new NoteListView();

        //fetching and integrating the view from FXML
        Parent view = noteListView.getView();
        this.noteList.getChildren().add(view);
    }
}

followme.fx是一个演示如何使用 afterburner.fx 的基本示例应用程序。由于 Maven 依赖项不兼容,我在直接运行 followme.fx 时确实遇到了一些问题,所以我 forked it's code并修复了一些阻止我开箱即用的问题。

评论中添加问题的答案

So from the NoteStore example, are you saying all I have to do is add the afterburner framework dependency and put @Inject on my model variable?

不,您还需要创建一个扩展 FXMLView 的关联类,并使用新调用对其进行实例化(类似于在上面的示例代码中创建 NotesListView 的方式)。如果您有兴趣继续研究 afterburner.fx 框架,请使用 followme.fx 项目作为基础,因为它为使用该框架的非常简单的可执行示例提供了完整的源代码。

I tried google guice and got it to work . . . you'll see in the constructor a game settings object is injected manually.

我认为您不应该像那样手动使用 Guice 注入(inject)器。我想你可以set a controller factory在 FXMLLoader 实例上启动注入(inject)。这就是 FXMLView在afterburner.fx 中做到了。 Guice 中使用的注入(inject)机制的确切细节将与 afterburner.fx 机制不同,但我认为设置 Controller 工厂的广义概念仍然相似。

在回答 Associating FXML and Controller in Guice's Module configuration 中有一个使用 FXML 和 Guice 设置 Controller 工厂的演示.

很遗憾,没有一种更直接的方法不会给您带来很多困难。

作为一个无关紧要的个人旁注,我对依赖注入(inject)框架的话题总体上有点矛盾。当然,它们可以提供帮助,但是对于简单的事情,我通常对带有 getInstance 方法的单例而不是更复杂的框架感到满意。不过我确实看到它们在大型项目中是如何有用的,当然它们在某些 Java 框架中非常流行。

关于java - 如何使用相同的模型对象初始化 JavaFX Controller ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20389567/

相关文章:

java - 如何从 TestNG 获取一份针对我所有测试用例的 junit 报告?

javascript - ReactJS 渲染从 Laravel Controller 作为 json 字符串传递的数据

java - 在 Activity 之外注入(inject)时如何使用 Dagger2 排列组件?

java - 如何在不显式调用的情况下注入(inject)值?

vba - 如何实现灵活的对象组合?

java - 重定向 View 上的空白页

javascript - angularjs:指令的访问 Controller

java - 表示 DFA 的数据结构

java - 将位图转换为 java.awt.image.BufferedImage

java - Intent.getStringExtra 上出现空指针异常。 : Android