Comment initialiser les controllers JavaFX avec le même objet model?

scénario

je crée une GUI où plusieurs vues font référence au même objet model.

Ce que je suis Habituer à

dans Swing, si je veux que toutes les vues de référence le même modèle, je passerais le modèle dans le constructeur.

Ce que je suis en train de Faire

En JavaFX, je suis de passage le modéliser en ayant une méthode de setter dans les vues/contrôleurs (menubars, Split panes, tabs, ...après chaque vue/contrôleur a été chargé. Je trouve cela très vulgaire et encombrant. De plus, je trouve que ça ne marchera pas parce que dans certaines situations j'ai besoin que le modèle existe déjà dans un controller avant que certains widgets de controller ne soient initialisés.

Terne "Alternatives 151950920"

(Note: je fais référence à ces stackoverflow questions:

  • Javafx 2.0 Comment-pour l'Application.getParameters () dans un contrôleur.fichier java
  • Passing Parameters JavaFX FXML
  • Plusieurs FXML avec les Contrôleurs, partager objet
  • paramètres de passage à un contrôleur lors du chargement D'un FXML )

  • Injection De Dépendance

    • j'ai regardé ce site web, http://www.zenjava.com/2011/10/23/javafx-2-0-fxml-and-spring / , et j'ai regardé un peu dans google Guice, mais je ne vois pas de façon simpliste de donner à chaque vue/controller JavaFX le même objet model. Il semblait que l'injection permettrait d'injecter un modèle différent pour chaque vue/contrôleur.
  • sauvegarde de l'objet modèle en tant que variable statique publique

    • C'est une option, mais pour le moment, je n'aime pas l'idée d'avoir un public static modèle ouvert et disponible. Évidemment, je peux en faire une variable statique privée et avoir getters et setters, mais je n'aime pas trop cette idée non plus.
  • passer les paramètres de L'appelant au contrôleur

    • je veux que chaque contrôleur se charge dans son constructeur, et je veux que chaque contrôleur personnalisé soit automatiquement injecté dans son contrôleur parent. Par exemple, l'onglet Vue d'ensemble de la carte se charge comme ceci:

      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();
          }
      }
      
    • et le contrôleur SingleGameSetup dispose de l'onglet Aperçu de la carte automatiquement injecté dans une variable:

      public class SingleGameSetupController extends AnchorPane {
      
          @FXML private CardOverviewTab cardOverviewTab;
      
          // Rest of the class
      }
      
    • et la partie de la fxml contenant l'onglet Aperçu de la carte ressemble à ceci:

      <CardOverviewTab fx:id="cardOverviewTab" />
      
    • de cette façon, je n'ai pas besoin de me soucier de charger manuellement un contrôleur, mais j'ai toujours le problème de définir le modèle.

  • réglage D'un contrôleur sur le FXMLLoader

    • cette option est similaire à ce à quoi je suis habitué, en passant le modèle comme paramètre dans le constructeur, mais il a encore le problème de charger manuellement les contrôleurs avec le FXMLLoader.
  • "151930920 De L'Événement" Bus

    • Je n'ai pas beaucoup lu sur ce sujet, mais d'après ce que j'ai lu, le bus d'événements semble être inactif et dépassé.
  • Singleton

    • c'est similaire à avoir un référence à l'objet model que les contrôleurs peuvent récupérer, mais encore une fois je cherche une meilleure solution. De Plus, je ne veux pas un singleton modèle.

ce que je cherche

y a-t-il un moyen de faire circuler l'objet modèle de manière moins encombrante? Je cherche un moyen aussi simple que de passer le modèle à un constructeur, mais je ne veux pas m'occuper du chargement manuel controllers via le FXMLLoader, ou paramétrage du model après le chargement des controllers. Peut-être avoir une classe pour récupérer le modèle est la meilleure option, mais je demande juste au cas où il ya une meilleure façon.

23
demandé sur Community 2013-12-05 05:18:09

3 réponses

mise à Jour

en plus du postcombustion.fx, aussi check-out Gluon Ignite :

Gluon Ignite permet aux développeurs d'utiliser des cadres d'injection de dépendances populaires dans leurs applications JavaFX, y compris à l'intérieur de leurs contrôleurs FXML. Gluon Ignite crée une abstraction commune sur plusieurs cadres d'injection de dépendances populaires (actuellement Guice, Spring, et Dagger, mais nous planifions à ajouter plus que la demande devient évidente). Avec le support complet de Jsr-330 Gluon Ignite rend l'utilisation de l'injection de dépendance dans les applications JavaFX triviale.

Injection d'objets modèles dans les contrôleurs est aussi via @Inject, similaire à afterburner.fx.

Approche Suggérée

comme vous semblez être à la recherche d'un cadre d'injection de dépendances, je pense que votre meilleure option est d'utiliser le postcombustion.fx cadre .

postcombustion.fx fournit un moyen d'injecter des objets model dans vos controllers JavaFX en utilisant L'annotation Java standard @Inject .

Alternative À La Dépendance Des Systèmes D'Injection

ressort est grand et compliqué et, à moins que vous ayez besoin d'une grande partie de ses autres fonctionnalités pour votre application, ne devrait pas être considérée en raison de sa complexité.

Guice est beaucoup plus simple que le ressort et un choix raisonnable si vous avez besoin d'un cadre d'injection de dépendance avec de nombreuses fonctionnalités telles que les classes de fournisseurs. Mais à partir du son de celui-ci, vous n'avez pas besoin de toutes les fonctionnalités que Guice fournit comme vous voulez juste un moyen de passer autour des instances singleton d'objets dans votre application sans les chercher explicitement.

donc, essayez postburner.fx et voir si elle correspond à vos besoins.

postcombustion.FX code D'échantillon

voici un exemple d'injection d'une instance modèle (la NotesStore ) dans un contrôleur utilisant afterburner.fx. L'échantillon est directement copié à partir du postcombustion .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 est une application d'échantillon de base démontrant comment utiliser postcombustion.fx. J'ai eu quelques problèmes à obtenir le régime emporte-moi.fx qui court tout droit de la boîte en raison d'incompatibilités de dépendance Maven, donc je bifurqué son code et corrigé certains des problèmes qui m'ont empêché de l'utiliser hors de la boîte.

réponses aux questions supplémentaires des commentaires

donc, d'après L'exemple de NoteStore, est-ce que vous dites que tout ce que j'ai à faire est d'ajouter la dépendance du framework afterburner et de mettre @Inject sur ma variable modèle?

Non, vous devez aussi créer une classe associée qui étend FXMLView et instancie cela avec un nouvel appel (similaire à la façon dont NotesListView est créé dans l'exemple de code ci-dessus). Si vous êtes intéressé pour continuer à étudier la postcombustion.FX framework, puis utiliser le followme.FX project comme base car il fournit le code source complet pour un échantillon exécutable très simple en utilisant le framework.

j'ai essayé google guice et je l'ai fait fonctionner . . . vous verrez dans le constructeur qu'un objet game settings est injecté manuellement.

Je ne pense pas que vous devriez avoir à utiliser l'injecteur Guice manuellement comme ça. Je pense que vous pouvez régler une usine de contrôleur sur une instance Fxmllloader pour lancer l'injection. C'est ainsi que le FXMLView dans afterburner.fx le fait. Les détails de l'injection mécanisme utilisé dans Guice va différer de la postcombustion.fx mécanisme, mais je pense que le concept général de réglage de l'usine de contrôleur reste similaire.

il y a une démo du contrôleur set factory utilisant FXML et Guice dans la réponse à: associant FXML et le contrôleur dans la configuration du Module de Guice .

c'est dommage qu'il n'y ait pas une façon plus directe de faire cela qui ne vous cause pas tant de difficultés.

comme un remarque, je suis un peu ambivalent sur le sujet des cadres d'injection de dépendances en général. Bien sûr, ils peuvent aider, mais souvent pour des choses simples je suis OK avec un singleton avec une méthode de gettinstance plutôt que le cadre plus sophistiqué. Je vois quand même comment dans les projets plus importants ils peuvent être utiles et certainement ils sont très populaires dans certains cadres Java.

15
répondu jewelsea 2017-05-23 11:46:20

j'ai fait des recherches sur ce problème et j'ai trouvé que l'injection de dépendance avec un singleton (pour le modèle) est ma conception optimale. J'ai appris que le fait d'avoir une méthode de setter pour le modèle dans chacun de mes contrôleurs est une forme d'injection de dépendance comme le fait de passer le modèle à travers le constructeur. Spring et Guice sont des cadres pour aider à cela.

j'ai essayé D'utiliser le ressort comme noté ici: http://www.zenjava.com/2011/10/23/better-controller-injection / mais j'ai rencontré le problème quand la classe de configuration a essayé de charger un contrôleur, elle n'a pas chargé les contrôleurs membres. Ce n'était peut-être pas un problème de printemps, mais je me suis dit que je ne me souciais pas assez de passer le temps de le faire fonctionner. De plus, j'aurais dû passer en revue tous mes fichiers de controller et éditer la façon dont ils ont été créés.

ayant cherché partout et faisant beaucoup de lecture, je trouvé que cet article exprime le mieux ce que je voudrais pouvoir faire: https://forums.oracle.com/thread/2301217?tstart=0 . Comme L'article fait référence à des améliorations suggérées, ces améliorations n'existent pas encore dans JavaFX. Mais quand ils le feront, je les mettrai en œuvre. Juste pour un exemple, pouvoir injecter un modèle via la fxml:

<usevar name="model" type="com.mycom.myapp.ModelObject"/>
0
répondu j will 2013-12-12 05:57:57

le cadre DataFX a une nouvelle API appelée DataFX-Flow. Avec cette API, vous pouvez simplement injecter des objets dans un contrôleur de vue. Autre que post-combustion.les portées fx sont supportées ici. Vous pouvez trouver un exemple ici: http://www.guigarage.com/2013/12/datafx-controller-framework-preview/

0
répondu Hendrik Ebbers 2014-01-24 18:44:08