如何使用相同的模型对象初始化 JavaFX 控制器? [英] How to initialize JavaFX controllers with the same model object?

查看:38
本文介绍了如何使用相同的模型对象初始化 JavaFX 控制器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

场景

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

I am creating a GUI where multiple views reference the same model object.

我习惯的东西

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

In Swing, if i want all the views to reference the same model i would pass the model into the constructor.

我目前在做什么

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

In JavaFX, I am passing the model around by having a setter method in the views/controllers (menubars, split panes, tabs, ...), after each view/controller has been loaded. I find this very tacky and cumbersome. Additionally, I find it won't work because in certain situations i need the model to already exist in a controller before some of the controller widgets are initialized.

乏善可陈的替代品

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

(Note: I am referencing these stackoverflow questions:

依赖注入

  • I've looked at this website, http://www.zenjava.com/2011/10/23/javafx-2-0-fxml-and-spring/, and i have looked a little into google Guice, but I don't see a way of simplistically giving each JavaFX view/controller the same model object. It seemed like the injection would inject a different model for each view/controller.

将模型对象保存为公共静态变量

Saving the model object as a public static variable

  • 这是一个选项,但目前我不喜欢拥有如此开放和可用的公共静态模型的想法.显然,我可以将其设为私有静态变量并具有 getter 和 setter,但我也不太喜欢这个想法.

从调用者向控制器传递参数

Passing Parameters from Caller to Controller

  • 我希望每个控制器在其构造函数中加载自身,并且我希望每个自定义控制器自动注入到其父控制器中.例如,卡片概览选项卡的加载方式如下:

  • I want each controller to load itself in its constructor, and I want each custom controller to be automatically injected into its parent controller. For example, the card overview tab loads itself like this:

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 控制器将卡片概览选项卡自动注入到变量中:

  • And the SingleGameSetup controller has the card overview tab automatically injected into a variable:

    public class SingleGameSetupController extends AnchorPane {
    
        @FXML private CardOverviewTab cardOverviewTab;
    
        // Rest of the class
    }
    

  • 包含卡片概览选项卡的 fxml 部分如下所示:

  • And the part of the fxml containing the card overview tab looks like this:

    <CardOverviewTab fx:id="cardOverviewTab" />
    

  • 这样我就不用担心手动加载控制器了,但是我仍然有设置模型的问题.

  • This way I do not need to worry about manually loading a controller, but I still have the problem of setting the model.

    在 FXMLLoader 上设置控制器

    Setting a Controller on the FXMLLoader

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

    事件总线

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

    单身

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

    我在找什么

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

    Is there a way to pass the model object around in a less cumbersome way? I am looking for a way that is as simple as passing the model to a constructor, but I do not want to deal with manually loading controllers via the FXMLLoader, or setting the model after the controllers are loaded. Maybe having a class to retrieve the model is the best option, but I am asking just in case there is a better way.

    推荐答案

    更新

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

    In addition to afterburner.fx, also checkout Gluon Ignite:

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

    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,类似于afterburner.fx.

    Injection of model objects into controllers is also via @Inject, similar to afterburner.fx.

    建议的方法

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

    As you appear to be seeking a dependency injection framework, I think your best option is to use the afterburner.fx framework.

    afterburner.fx 提供了一种使用标准 Java @Inject 注释.

    afterburner.fx provides a way injecting model objects into your JavaFX controllers using the standard Java @Inject annotation.

    替代依赖注入系统

    Spring 既庞大又复杂,除非您的应用程序需要它的许多其他功能,否则由于其复杂性,不应考虑它.

    Spring is large and complicated and, unless you need a lot of its other functionality for your application, should not be considered due to its complexity.

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

    Guice is a lot simpler than Spring and a reasonable pick if you need a dependency injection framework with numerous features such as provider classes. But from the sound of it, you don't need all the features that Guice provides as you just want to a way to pass around singleton instances of objects in your application without explicitly looking them up.

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

    So, try out afterburner.fx and see if it fits your needs.

    afterburner.fx 示例代码

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

    Here is sample of injecting a model instance (the NotesStore) into a controller using afterburner.fx. The sample is directly copied from the 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 开箱即用时遇到了一些问题,所以我 分叉它是代码并修复了一些使我无法立即使用它的问题.

    followme.fx is a basic sample application demonstrating how to use afterburner.fx. I did have a few issues getting followme.fx running straight out of the box due to Maven dependency incompatibilities, so I forked it's code and fixed some of the issues which prevented me from using it out of the box.

    对评论中附加问题的回答

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

    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 项目作为基础,因为它为使用该框架的非常简单的可执行示例提供了完整的源代码.

    No, you also need to create an associated class that extends FXMLView and instantiate that with a new call (similar to how NotesListView is created in the sample code above). If you are interested in continuing to investigate the afterburner.fx framework, then use the followme.fx project as basis because it provides complete source code for a very simple executable sample using the framework.

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

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

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

    I don't think you should have to use the Guice injector manually like that. I think you can set a controller factory on an FXMLLoader instance to initiate the injection. This is how the FXMLView in afterburner.fx does it. The exact detail of the injection mechanism used in Guice is going to differ from the afterburner.fx mechanism, but I think the broad concept of setting the controller factory remains similar.

    在答案中有一个使用 FXML 和 Guice 的 set controller factory 的演示:Guice 的模块配置中关联 FXML 和控制器.

    There is a demo of the set controller factory using FXML and Guice in the answer to: Associating FXML and Controller in Guice's Module configuration.

    很遗憾,没有一种更直接的方法可以做到这一点,不会给您带来这么多困难.

    It's a shame there is not a more straightforward way of doing this which does not cause you so many difficulties.

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

    As an inconsequential personal side note, I'm kind of ambivalent on the topic of dependency injection frameworks in general. Sure, they can help, but many times for simple things I'm often OK with a singleton with a getInstance method rather than the more sophisticated framework. Still I do see how in larger projects they can be useful and certainly they are very popular in certain Java frameworks.

    这篇关于如何使用相同的模型对象初始化 JavaFX 控制器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆