草庐IT

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

coder 2023-05-16 原文

场景

我正在创建一个 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 - 如何使用相同的模型对象初始化 JavaFX Controller ?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  4. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  5. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  6. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  7. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  8. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  9. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  10. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

随机推荐