如何使用相同的模型对象初始化JavaFX控制器?

j w*_*ill 26 java dependency-injection controller javafx fxml

脚本

我正在创建一个GUI,其中多个视图引用相同的模型对象.

我习惯了什么

在Swing中,如果我希望所有视图都引用相同的模型,我会将模型传递给构造函数.

我目前正在做什么

在JavaFX中,我通过在每个视图/控制器加载后在视图/控制器(菜单栏,拆分窗格,制表符......)中设置setter方法来传递模型.我发现这非常俗气和笨重.另外,我发现它不起作用,因为在某些情况下我需要在初始化某些控制器小部件之前模型已经存在于控制器中.

Lackluster Alternatives

(注意:我正在引用这些stackoverflow问题:

  • Controller.java文件中的Javafx 2.0操作方法Application.getParameters()
  • 传递参数JavaFX FXML
  • 带控制器的多个FXML,共享对象
  • 加载FXML时将参数传递给控制器)

  • 依赖注入

    • 我看过这个网站,http: //www.zenjava.com/2011/10/23/javafx-2-0-fxml-and-spring/,我看了一下google Guice,但我不知道看不到简单地给每个JavaFX视图/控制器提供相同模型对象的方法.看起来注入会为每个视图/控制器注入不同的模型.
  • 将模型对象保存为公共静态变量

    • 这是一个选项,但目前我不喜欢让公共静态模型如此开放和可用的想法.显然,我可以使它成为一个私有静态变量,并有getter和setter,但我也不喜欢这个想法.
  • 将参数从调用者传递到控制器

    • 我希望每个控制器在其构造函数中加载自身,并且我希望每个自定义控制器自动注入其父控制器.例如,卡片概述选项卡会像这样加载自身:

      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();
          }
      }
      
      Run Code Online (Sandbox Code Playgroud)
    • 并且SingleGameSetup控制器将卡概述选项卡自动注入变量:

      public class SingleGameSetupController extends AnchorPane {
      
          @FXML private CardOverviewTab cardOverviewTab;
      
          // Rest of the class
      }
      
      Run Code Online (Sandbox Code Playgroud)
    • 包含卡片概述选项卡的fxml部分如下所示:

      <CardOverviewTab fx:id="cardOverviewTab" />
      
      Run Code Online (Sandbox Code Playgroud)
    • 这样我不需要担心手动加载控制器,但我仍然有设置模型的问题.

  • 在FXMLLoader上设置控制器

    • 此选项与我习惯的类似,将模型作为参数传递给构造函数,但它仍然存在使用FXMLLoader手动加载控制器的问题.
  • 活动巴士

    • 我没有读太多内容,但从我所看到的事件总线似乎是不活跃和过时的.
  • 独生子

    • 这类似于对控制器可以检索的模型对象的公共静态引用,但我再次寻找更好的解决方案.另外,我不想要单身模型.

我在寻找什么

有没有办法以不那么繁琐的方式传递模型对象?我正在寻找一种简单的方法,如将模型传递给构造函数,但我不想处理通过FXMLLoader手动加载控制器,或者在加载控制器后设置模型.也许有一个类来检索模型是最好的选择,但我要求以防万一有更好的方法.

jew*_*sea 16

更新

除了afterburner.fx,还要结帐Gluon Ignite:

Gluon Ignite允许开发人员在他们的JavaFX应用程序中使用流行的依赖注入框架,包括在他们的FXML控制器中.Gluon Ignite在几个流行的依赖注入框架(目前是Guice,Spring和Dagger)上创建了一个共同的抽象,但随着需求变得明显,我们计划增加更多.在JSR-330的完全支持下,Gluon Ignite使JavaFX应用程序中的依赖注入变得微不足道.

将模型对象注入控制器也是通过@Inject,类似于afterburner.fx.

建议的方法

当您正在寻求依赖注入框架时,我认为您最好的选择是使用afterburner.fx框架.

afterburner.fx提供了一种使用标准Java @Inject批注将模型对象注入JavaFX控制器的方法.

替代依赖注入系统

Spring非常庞大而且复杂,除非您的应用程序需要很多其他功能,否则不应该考虑它的复杂性.

如果你需要一个具有许多功能的依赖注入框架,例如提供者类,Guice比Spring简单得多,也是一个合理的选择.但是从它的声音来看,你不需要Guice提供的所有功能,因为你只想在应用程序中传递对象的单例实例,而无需明确查找它们.

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

afterburner.fx示例代码

以下是NotesStore使用afterburner.fx 将模型实例(the )注入控制器的示例.样本直接从afterburner.fx文档中复制.

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

followme.fx是一个基本的示例应用程序,演示了如何使用afterburner.fx.由于Maven依赖项不兼容,我确实有一些问题让followme.fx直接开箱即用,所以我分叉了它的代码并修复了一些阻止我开箱即用的问题.

来自评论的补充问题的答案

那么从NoteStore示例中,您是否说我要做的就是添加afterburner框架依赖项并将@Inject放在我的模型变量上?

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

我尝试了谷歌guice并让它工作...您将在构造函数中看到手动注入游戏设置对象.

我不认为你应该像这样手动使用Guice注射器.我认为你可以在FXMLLoader实例上设置一个控制器工厂来启动注入.这就是afterburner.fx中FXMLView的功能.Guice中使用的注入机制的确切细节将与afterburner.fx机制不同,但我认为设置控制器工厂的广泛概念仍然相似.

在答案中有一个使用FXML和Guice的设置控制器工厂的演示:在Guice的模块配置中关联FXML和Controller.

遗憾的是,没有更简单的方法可以做到这一点,这不会给你带来太多困难.

作为一个无关紧要的个人注释,我总体上对依赖注入框架的主题感到矛盾.当然,他们可以提供帮助,但很多时候对于简单的事情,我通常可以使用带有getInstance方法的单例,而不是更复杂的框架.我仍然看到在大型项目中它们如何有用,当然它们在某些Java框架中非常流行.