web-dev-qa-db-fra.com

Comment initialiser les contrôleurs JavaFX avec le même objet de modèle?

Scénario

Je crée une interface utilisateur graphique où plusieurs vues font référence au même objet de modèle. 

A quoi je suis habitué 

Dans Swing, si je veux que toutes les vues fassent référence au même modèle, je passe le modèle au constructeur. 

Ce que je fais actuellement

En JavaFX, je passe du modèle à une méthode de définition dans les vues/contrôleurs (barres de menu, volets divisés, onglets, ...), après le chargement de chaque vue/contrôleur. Je trouve cela très collant et encombrant. De plus, je constate que cela ne fonctionnera pas car, dans certaines situations, le modèle doit déjà exister dans un contrôleur avant que certains des widgets de contrôleur ne soient initialisés.

Alternatives peu recommandables

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

  • Javafx 2.0 How-to Application.getParameters () dans un fichier Controller.Java
  • Paramètres de passage JavaFX FXML
  • Plusieurs FXML avec contrôleurs, objet partagé
  • Passer des paramètres à un contrôleur lors du chargement d'un FXML )

  • Injection de dépendance

    • J'ai consulté ce site Web, http://www.zenjava.com/2011/10/23/javafx-2-0-fxml-and-spring/ et j'ai examiné un peu Google Guice , mais je ne vois pas comment donner à chaque vue/contrôleur JavaFX le même objet de modèle. Il semblait que l'injection injecterait un modèle différent pour chaque vue/contrôleur.
  • Enregistrement de l'objet de modèle en tant que variable statique publique

    • C'est une option, mais pour le moment je n'aime pas l'idée de disposer d'un modèle statique public aussi ouvert et disponible. De toute évidence, je peux en faire une variable statique privée et avoir des accesseurs, mais je n'aime pas trop cette idée. 
  • Passage des paramètres de l'appelant au contrôleur

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

      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 a l'onglet de vue d'ensemble de la carte automatiquement injecté dans une variable:

      public class SingleGameSetupController extends AnchorPane {
      
          @FXML private CardOverviewTab cardOverviewTab;
      
          // Rest of the class
      }
      
    • Et la partie du fxml contenant l'onglet Vue d'ensemble de la carte se présente comme suit:

      <CardOverviewTab fx:id="cardOverviewTab" />
      
    • De cette façon, je n'ai pas à m'inquiéter du chargement manuel d'un contrôleur, mais j'ai toujours le problème de la configuration du modèle.

  • Définir un contrôleur sur le FXMLLoader

    • Cette option est similaire à celle à laquelle je suis habitué, en passant le modèle en tant que paramètre dans le constructeur, mais elle a toujours le problème de charger les contrôleurs manuellement avec FXMLLoader. 
  • Bus d'événement

    • Je n'ai pas lu beaucoup de choses là-dessus, mais d'après ce que j'ai lu, le bus d'événements semble être inactif et obsolète.
  • Singleton

    • Cela revient à avoir une référence statique publique à l'objet de modèle que les contrôleurs peuvent récupérer, mais là encore, je cherche une meilleure solution. De plus, je ne veux pas de modèle singleton.

Ce que je cherche

Existe-t-il un moyen de faire passer l'objet de modèle de manière moins encombrante? Je cherche un moyen aussi simple que de transmettre le modèle à un constructeur, mais je ne souhaite pas traiter le chargement manuel des contrôleurs via FXMLLoader, ni configurer le modèle après le chargement des contrôleurs. Avoir un cours pour récupérer le modèle est peut-être la meilleure option, mais je demande juste au cas où il y aurait un meilleur moyen.

23
j will

J'ai étudié ce problème et j'ai constaté que l'injection de dépendance avec un singleton (pour le modèle) est ma conception optimale. J'ai appris qu'avoir une méthode de définition du modèle dans chacun de mes contrôleurs est une forme d'injection de dépendance, tout comme le fait de faire passer le modèle par le constructeur. Spring et Guice sont des cadres pour aider cela. 

J'ai essayé d'utiliser Spring comme indiqué ci-dessous: http://www.zenjava.com/2011/10/23/better-controller-injection/ mais j'ai rencontré le problème lorsque la classe de configuration a essayé de charger un contrôleur, il n'a pas été possible de charger les contrôleurs membres. Ce n’était peut-être pas un numéro du printemps, mais j’ai pensé que je ne me souciais pas assez de passer le temps de le faire fonctionner. De plus, il aurait fallu que je consulte tous mes fichiers de contrôleur et modifie la manière dont ils ont été créés.

Après avoir fait des recherches et lu beaucoup, j'ai trouvé que cet article exprime le mieux ce que j'aimerais pouvoir faire: https://forums.Oracle.com/thread/2301217?tstart=0 . Étant donné que l'article fait référence aux améliorations suggérées, ces améliorations n'existent pas encore dans JavaFX. Mais quand ils le feront, je les appliquerai. Juste à titre d'exemple, être capable d'injecter un modèle via le fxml:

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

DataFX Framework dispose d'une nouvelle API appelée DataFX-Flow. Avec cette API, vous pouvez simplement injecter des objets dans un contrôleur de vue. Les autres étendues Afterburner.fx sont prises en charge ici. Vous pouvez trouver un exemple ici: http://www.guigarage.com/2013/12/datafx-controller-framework-preview/

0
Hendrik Ebbers