web-dev-qa-db-ja.com

JavaFXコントローラーを同じモデルオブジェクトで初期化する方法は?

シナリオ

複数のビューが同じモデルオブジェクトを参照するGUIを作成しています。

私が慣れていること

Swingでは、すべてのビューに同じモデルを参照させたい場合、モデルをコンストラクターに渡します。

私が現在していること

JavaFXでは、各ビュー/コントローラーが読み込まれた後、ビュー/コントローラー(メニューバー、分割ペイン、タブなど)にセッターメソッドを設定することでモデルを渡します。これは非常に粘着性があり面倒です。さらに、特定の状況では、一部のコントローラーウィジェットが初期化される前にモデルがコントローラーに既に存在している必要があるため、機能しません。

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ビュー/コントローラーに同じモデルオブジェクトを単純に与える方法はわかりません。インジェクションは、ビュー/コントローラーごとに異なるモデルをインジェクトするように見えました。
  • モデルオブジェクトをパブリックな静的変数として保存する

    • これはオプションですが、現時点では、公開静的モデルを非常にオープンで利用可能にするという考えが好きではありません。明らかに、私はそれをプライベートな静的変数にし、ゲッターとセッターを持つことができますが、私はこの考えもあまり好きではありません。
  • 呼び出し元からコントローラーへのパラメーターの受け渡し

    • 各コントローラーをコンストラクターにロードし、各カスタムコントローラーを親コントローラーに自動的に挿入するようにします。たとえば、カード概要タブは次のようにロードされます。

      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コントローラーには、変数に自動的に挿入されるカード概要タブがあります。

      public class SingleGameSetupController extends AnchorPane {
      
          @FXML private CardOverviewTab cardOverviewTab;
      
          // Rest of the class
      }
      
    • また、カード概要タブを含むfxmlの部分は次のようになります。

      <CardOverviewTab fx:id="cardOverviewTab" />
      
    • この方法では、コントローラーを手動でロードすることを心配する必要はありませんが、モデルを設定する問題がまだあります。

  • FXMLLoaderでコントローラーを設定する

    • このオプションは、モデルをパラメーターとしてコンストラクターに渡すことに慣れていますが、FXMLLoaderを使用してコントローラーを手動で読み込むという問題があります。
  • イベントバス

    • 私はこれについてあまり読みませんでしたが、私が読んだことから、イベントバスは非アクティブで時代遅れのようです。
  • シングルトン

    • これは、コントローラーが取得できるモデルオブジェクトへのパブリックな静的参照を持つことに似ていますが、より良いソリューションを探しています。さらに、シングルトンモデルは必要ありません。

探しているもの

それほど面倒ではない方法でモデルオブジェクトを渡す方法はありますか?モデルをコンストラクターに渡すのと同じくらい簡単な方法を探していますが、FXMLLoaderを使用してコントローラーを手動でロードしたり、コントローラーのロード後にモデルを設定したりすることは避けたいです。モデルを取得するクラスを用意するのが最善の選択肢かもしれませんが、より良い方法がある場合に備えて質問しています。

26
j will

更新

Afterburner.fxに加えて、 Gluon Ignite もチェックアウトします。

Gluon Igniteを使用すると、開発者はFXMLコントローラー内など、JavaFXアプリケーションで一般的な依存性注入フレームワークを使用できます。 Gluon Igniteは、いくつかの一般的な依存関係注入フレームワーク(現在はGuice、Spring、およびDagger)に対して共通の抽象化を作成しますが、需要が明らかになったらさらに追加する予定です。 JSR-330 Gluon Igniteを完全にサポートすることにより、JavaFXアプリケーションで依存性注入を簡単に使用できます。

モデルオブジェクトのコントローラーへの注入も、afterburner.fxと同様に@Injectを介して行われます。

推奨されるアプローチ

依存性注入フレームワークを探しているように見えるので、あなたの最良のオプションは afterburner.fx framework を使用することだと思います。

afterburner.fxは、標準Java @ Inject アノテーションを使用して、モデルオブジェクトをJavaFXコントローラーに注入する方法を提供します。

代替依存性注入システム

Springは大きく複雑です。アプリケーションに他の多くの機能が必要でない限り、Springは複雑であるため考慮すべきではありません。

GuiceはSpringよりもはるかに単純で、プロバイダークラスなどの多数の機能を備えた依存関係注入フレームワークが必要な場合には、妥当な選択肢です。しかし、その見た目からは、Guiceが提供するすべての機能は必要ありません。明示的に検索せずに、アプリケーション内のオブジェクトのシングルトンインスタンスを渡す方法が必要なだけです。

したがって、afterburner.fxを試して、ニーズに合っているかどうかを確認してください。

afterburner.fxサンプルコード

以下は、afterburner.fxを使用してモデルインスタンス(NotesStore)をコントローラーに注入するサンプルです。サンプルは 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を実行するのにいくつかの問題があったので、 コードをfork フォークし、使用を妨げていたいくつかの問題を修正しました箱から出して。

コメントからの追加質問に対する回答

では、NoteStoreの例から、アフターバーナーフレームワークの依存関係を追加し、モデル変数に@Injectを追加するだけでいいと言っていますか?

いいえ、FXMLViewを拡張する関連クラスを作成し、新しい呼び出しでインスタンス化する必要もあります(上記のサンプルコードでNotesListViewを作成する方法と同様)。 afterburner.fxフレームワークの調査を続けたい場合は、フレームワークを使用する非常に単純な実行可能サンプルの完全なソースコードを提供するため、followme.fxプロジェクトをベースとして使用します。

グーグルguiceを試してみて、動作するようにしました。 。 。コンストラクターには、ゲーム設定オブジェクトが手動で挿入されます。

そのように手動でGuiceインジェクターを使用する必要があるとは思わない。 コントローラーのファクトリー をFXMLLoaderインスタンスに設定して、注入を開始できると思います。これは、afterburner.fxの FXMLView が行う方法です。 Guiceで使用されるインジェクションメカニズムの正確な詳細は、afterburner.fxメカニズムとは異なりますが、コントローラーファクトリーを設定するという広い概念は同じままだと思います。

Guiceのモジュール構成 でFXMLとコントローラーを関連付けるには、FXMLとGuiceを使用したコントローラーセットファクトリーのデモがあります。

それほど多くの困難を引き起こさない、これを行うより簡単な方法がないのは残念です。

取るに足りない個人的なサイドノートとして、私は一般的に依存性注入フレームワークのトピックに関して一種の曖昧さを持っています。確かに、それらは助けになりますが、単純なことに対しては、より洗練されたフレームワークではなく、getInstanceメソッドを使用したシングルトンでしばしば大丈夫です。それでも、大規模なプロジェクトでどのように役立つか、また特定のJavaフレームワークで非常に人気があることは確かです。

16
jewelsea

私はこの問題を調査してきましたが、(モデルの)シングルトンとともに依存性注入が最適な設計であることがわかりました。各コントローラーにモデルのセッターメソッドを持つことは、コンストラクターを介してモデルを渡すのと同様に、依存関係の注入の一種であることを学びました。 SpringとGuiceはそれを支援するフレームワークです。

ここに記載されているようにSpringを使用してみました: http://www.zenjava.com/2011/10/23/better-controller-injection/ しかし、構成クラスを読み込もうとしたときに問題に遭遇しましたコントローラー、メンバーコントローラーの読み込みに失敗しました。これは春の問題ではなかったかもしれませんが、私はそれを機能させるために時間を費やすほど気にしなかったと考えました。さらに、コントローラーファイルをすべて調べて、作成方法を編集する必要がありました。

いろいろ調べて、多くの本を読んで、この記事が私ができることをしたいことを最もよく表していることがわかりました。 https://forums.Oracle.com/thread/2301217?tstart= =。この記事では提案された改善について言及しているため、これらの改善はJavaFXにはまだ存在していません。しかし、それらが実行されると、それらを実装します。ほんの一例として、fxmlを介してモデルを挿入できます。

<usevar name="model" type="com.mycom.myapp.ModelObject"/>
1
j will

DataFXフレームワークには、DataFX-Flowと呼ばれる新しいAPIがあります。このAPIを使用すると、View Controllerにオブジェクトを簡単に挿入できます。その他のAfterburner.fxスコープはここでサポートされています。ここに例を見つけることができます: http://www.guigarage.com/2013/12/datafx-controller-framework-preview/

0
Hendrik Ebbers