2015-03-25 3 views
2

Je programme une application avec javafx. C'est une application "multi-écran" avec un menu principal d'où je peux changer de scène.JavaFX inclut fxml dans fxml sans contrôleur

Mes scènes sont définies dans différents fichiers fxml. Parce que j'essaie d'utiliser le modèle mvc, je ne mets pas le contrôleur dans les fichiers fxml, j'utilise setController sur le FXMLloader.

Tout fonctionne bien, mais j'ai le menu principal et toutes ses fonctions pour l'onActions dans un contrôleur séparé et dans un fichier fxml séparé.

Je l'ai essayé avec

<fx:include source="Menubar.fxml"/> 

et créé un contrôleur pour le fichier FXML, quand je mis le contrôleur dans le fichier FXML je ne peux pas compiler la source. Comment définir le contrôleur pour le fichier fxml inclus?

startpage.fxml obtient son contrôleur "Startpage" avec

FXMLLoader loader = new FXMLLoader(getClass().getResource("../fxml/startpage.fxml")); 
     loader.setController(new Startpage(m)); 
     Pane mainPane = loader.load(); 

startpage.fxml comprend menubar.fxml, comment définir un contrôleur pour les commandes menubar maintenant? Ou comment inclure le menubarController facilement dans tous les autres contrôleurs?

Répondre

10

Je pense que vous devez utiliser un controllerFactory dans le chargeur pour réaliser ce que vous voulez ici. Lorsque vous utilisez un controllerFactory, vous spécifiez le nom de classe du contrôleur dans les fichiers FXML, mais la fabrique du contrôleur vous permet de contrôler la manière dont il est mappé à un objet (vous pouvez donc le construire en passant dans un modèle, etc.). Lorsque vous spécifiez un controllerFactory pour un FXMLLoader, cette fabrique est également utilisée pour créer les contrôleurs pour tout <fx:include> que vous avez dans le fichier FXML. Enfin, notez que vous pouvez injecter le contrôleur pour le fichier fxml inclus dans le fichier fxml "principal", tel que documenté dans le "Nested controllers" section of the FXML documentation.

Donc, si startpage.fxml ressemble à ceci:

<!-- imports etc --> 
<BorderPane fx:controller="com.example.Startpage" ... > 
    <top> 
    <fx:include source="Menubar.fxml" fx:id="menubar" /> 
    </top> 
    <!-- etc ... --> 
</BorderPane> 

et Menubar.fxml ressemble

<!-- imports etc --> 
<MenuBar fx:controller="com.example.MenubarController" ... > 
    <!-- etc... --> 
</MenuBar> 

Ensuite, vous pouvez contrôler l'instanciation des classes de contrôleur avec:

FXMLLoader loader = new FXMLLoader(getClass().getResource("../fxml/startpage.fxml")); 

Model m = ... ; 

Startpage startpageController = new Startpage(m); 
MenubarController menubarController = new MenubarController(m); 

Callback<Class<?>, Object> controllerFactory = type -> { 
    if (type == Startpage.class) { 
     return startpageController ; 
    } else if (type == MenubarController.class) { 
     return menubarController ; 
    } else { 
     // default behavior for controllerFactory: 
     try { 
      return type.newInstance(); 
     } catch (Exception exc) { 
      exc.printStackTrace(); 
      throw new RuntimeException(exc); // fatal, just bail... 
     } 
    } 
}; 

loader.setControllerFactory(controllerFactory); 

Pane mainPane = loader.load(); 

Vous avez maintenant des références aux deux contrôleurs dans votre code d'application, si vous en avez besoin, mais vous pouvez n aussi aussi

public class Startpage { 

    public final Model m ; 

    // note the name of this field must be xController, 
    // where x is the fx:id set on the <fx:include>: 

    @FXML 
    private final MenubarController menubarController ; 

    public Startpage(Model m) { 
     this.m = m ; 
    } 

    // ... 
} 

Le contrôleur principal a maintenant une référence au contrôleur de barre de menu.

+0

Bon, j'ai besoin de beaucoup plus de connaissances, je ne comprends pas votre réponse maintenant. Modifier. j'espérais que ça pourrait être facile comme "startpagecontroller extends menucontroller" ou quelque chose comme ça. Je pense que je laisserai toujours toutes les méthodes pour la barre de menu dans chaque contrôleur et le code fxml aussi ..:/ – Garog

+0

Je ne peux pas vraiment aider à moins que je sache quelles parties vous ne comprenez pas. Chaque fichier fxml est associé à un seul contrôleur * instance *. Le fichier fxml peut spécifier une * classe * pour le contrôleur.Ainsi, la fabrique de contrôleurs est une fonction qui indique au FXMLLoader comment obtenir l'instance du contrôleur à partir de la classe spécifiée. La duplication de méthodes ou la transformation d'un contrôleur en sous-classe ne vous aidera pas car vous disposez toujours de deux instances de contrôleur différentes (elles ne référenceront donc pas les mêmes données). –

+0

Les plus gros problèmes pour moi sont de comprendre votre solution (juste un débutant java) et/ou d'adapter votre exemple à mon code. Je vais essayer d'expliquer un peu plus pourquoi j'ai besoin de tout cela. Tout d'abord, comme j'ai commencé le projet, chaque fichier fxml avait son propre contrôleur, c'était bien, je pouvais inclure chaque fxml dans l'autre sans perdre aucune fonction. par exemple, j'ai eu une page dans l'application "createproject" cette page contient quelques champs de texte et inclus la barre de menu. quand j'ai utilisé les menuitems pour passer la page (scène) à "settingsforcreateproject" j'ai inclus à nouveau la barre de menu dans le nouveau fxml. – Garog