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

问题描述

情景



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



我习惯于



在Swing中,如果我想要所有参考相同模型的视图,我将把模型传递给构造函数。



我目前正在做的



在JavaFX中,我传递了模型在每个视图/控制器加载后,在views / controllers(菜单栏,分割窗格,选项卡,...)中设置setter方法。我觉得这很麻烦和麻烦。另外,我发现它不会工作,因为在某些情况下,我需要一些控制器中的模型已经存在于控制器的某些部件初始化之前。



Lackluster替代方案



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








  • 依赖注入




    • 我看过这个网站,,我已经看到一点点google,但我看不到一种简单地给每个JavaFX视图/控制器相同的模型对象的方式。似乎注入将为每个视图/控制器注入不同的模型。


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




    • 这是一个选项,但目前我不喜欢让公共静态模型如此开放和可用。显然,我可以使它成为一个私有的静态变量,并有getter和setter,但我也不喜欢这个想法。


  • 将参数从Caller传递给Controller




    • 我希望每个控制器在其构造函数中加载自身,我希望每个自定义控制器都自动注入到其父控制器中。例如,卡概述标签加载自身如下:

        public CardOverviewTab(){
      FXMLLoader fxmlLoader =新的FXMLLoader (的getClass()的getResource( card_overview_tab.fxml));
      fxmlLoader.setRoot(content);
      fxmlLoader.setController(this);

      尝试{
      fxmlLoader.load();
      } catch(Exception e){
      e.printStackTrace();
      }
      }


    • 并且SingleGameSetup控制器具有卡概述标签自动注入到变量中:

        public class SingleGameSetupController extends AnchorPane {

      @FXML private CardOverviewTab cardOverviewTab ;

      //其他类
      }


    • 并且包含卡概述标签的fxml的部分如下所示:

       < CardOverviewTab fx:id =cardOverviewTab /> 


    • 这样我就不需要担心手动加载控制器,但是我还是设置模型的问题。



  • 在FXMLLoader上设置控制器




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


  • 事件总线




    • 我没有读过太多的东西,但是从我所看到的事件总线似乎不活跃和过时。


  • Singleton




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




我正在寻找



有没有办法以较不笨重的方式传递模型对象?我正在寻找一种简单的方式将模型传递给构造函数,但是我不想处理通过FXMLLoader手动加载控制器,或者在加载控制器后设置模型。也许有一个类来检索模型是最好的选择,但是我想询问是否有更好的方法。

解决方案

更新



除了afterburner.fx之外,还检出:

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



建议的方法



似乎正在寻找依赖注入框架,我认为你最好的选择是使用 。



afterburner.fx提供了使用标准Java 注释。



替代依赖注入系统



Spring是大而复杂的,除非你对于您的应用程序需要很多其他功能,不应该考虑其复杂性。



Guice比Spring简单得多,如果您需要一个合理的选择依赖注入框架,具有许多功能,如提供程序类。但是从声音来看,您不需要Guice提供的所有功能,因为您只想通过一种方式来绕过应用程序中的对象的单例实例,而无需显式查看。



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



afterburner.fx示例代码 p>

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

  import com.airhacks.afterburner.views.FXMLView; 

public class NoteListView扩展FXMLView {
//通常无关紧要,FXML和CSS自动
//加载和实例化
}

public class AirpadPresenter实现可初始化{
@Inject //由afterburner注入,零配置需要
NotesStore存储;

@FXML //由FXML注入
AnchorPane noteList;

@Override
public void initialize(URL url,ResourceBundle rb){
//从FXML构造的视图
NoteListView noteListView = new NoteListView();

//从FXML获取并集成视图
父视图= noteListView.getView();
this.noteList.getChildren()。add(view);
}
}

是演示如何使用afterburner.fx的基本示例应用程序。由于Maven依赖关系不兼容,我确实有几个问题让followme.fx直接运行,因此我,并修复了一些阻止我使用它的问题。



来自评论的其他问题的答案

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

我不认为你应该使用Guice注射器手动这样。我想你可以以启动注入。这就是。



这是一个耻辱,没有一个更直接的方式来做,这不会导致你这么多困难。



作为一个无关紧要的个人附注,我对于依赖注入框架的一般主题是一种矛盾的。当然,他们可以帮助,但是很多时候,简单的事情我常常可以通过一个单一的getInstance方法,而不是更复杂的框架。仍然我确实看到在大型项目中他们可以是有用的,当然他们在某些Java框架中非常受欢迎。


Scenario

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

What I am Accustom to

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

What I am Currently Doing

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.

Lackluster Alternatives

(Note: I am referencing these stackoverflow questions:

  • 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)

  • Dependency Injection

    • 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

    • This is an option but at the moment I don't like the idea of having a public static model so open and available. Obviously, I can make it a private static variable and have getters and setters, but i don't like this idea much either.
  • 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();
          }
      }
      

    • 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
      }
      

    • 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.

  • Setting a Controller on the FXMLLoader

    • This option is similar to what I am accustom to, passing the model as a parameter into the constructor, but it still has the problem of loading controllers manually with the FXMLLoader.
  • Event Bus

    • I haven't read too much into this, but from what I have read the event bus seems to be inactive and outdated.
  • Singleton

    • This is similar to having a public static reference to the model object that controllers can retrieve, but again I am looking for a better solution. Plus, I do not want a singleton model.

What I am Looking for

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.

解决方案

Update

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

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

Suggested Approach

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

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

Alternative Dependency Injection Systems

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 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.

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

afterburner.fx Sample Code

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 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.

Answers to addition questions from comments

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.

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.

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.

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控制器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-29 12:47
查看更多