IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JavaFX Discussion :

[JavaFX 8] Découper une application en plusieurs vues FXML


Sujet :

JavaFX

  1. #1
    Membre du Club
    Inscrit en
    Février 2005
    Messages
    242
    Détails du profil
    Informations personnelles :
    Âge : 32

    Informations forums :
    Inscription : Février 2005
    Messages : 242
    Points : 63
    Points
    63
    Par défaut [JavaFX 8] Découper une application en plusieurs vues FXML
    Bonjour,

    Je développe un petit client mail avec JavaFX.

    Nom : client-mail-mainview.png
Affichages : 2741
Taille : 43,5 Ko

    Voici ma fenêtre principale (RootLayout), elle est composée comme ceci :

    • BorderPane
      • un SplitPane vertical qui sépare la liste de dossier (folderList) des deux autres
      • dans la partie droite, un autre SplitPane horizontale cette fois, qui sépare la liste de message en haut (messageList) de la visualisation des messages en bas (messageViewer)


    Chaque SplitPane fourni chacun deux AnchorPane dans lequel je veux appeler d'autres vues FXML (respectivement folderList, messageList et messageViewer).

    J'ai donc créer un contrôleur RootLayoutController, qui charge les trois fichiers FXML de mes sous-vues. Chacun des AnchorPane concerné à un fx:id que je fais correspondre à des champs dans ce contrôleur.

    Voici le code de la classe principale, MainApp :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    package org.speechmail.client;
     
    import java.io.IOException;
     
    import org.speechmail.client.views.RootLayoutController;
     
    import javafx.application.Application;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Scene;
    import javafx.scene.layout.BorderPane;
    import javafx.stage.Stage;
     
    public class MainApp extends Application {
     
    	private Stage primaryStage;
        private BorderPane rootLayout;
     
        @Override
        public void start(Stage primaryStage) {
            this.primaryStage = primaryStage;
            this.primaryStage.setTitle("Client mail");
     
            initRootLayout();
        }
     
        /**
         * Initializes the root layout.
         */
        public void initRootLayout() {
            try {
                FXMLLoader loader = new FXMLLoader(MainApp.class.getResource("views/fxml/RootLayout.fxml"));
                this.rootLayout = (BorderPane) loader.load();
     
                RootLayoutController controller = loader.<RootLayoutController>getController();
                controller.setMainApp(this);
     
                Scene scene = new Scene(rootLayout);
                primaryStage.setScene(scene);
                primaryStage.show();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }	
     
        /**
         * Returns the main stage.
         * @return
         */
        public Stage getPrimaryStage() {
            return primaryStage;
        }
     
    	public static void main(String[] args) {
    		launch(args);
    	}
    }
    Elle créé la fenêtre, charge le FXML rootLayout et en récupère le contrôleur (RootLayoutController, spécifié dans l'attribut fx:controller)

    Voici le code du contrôleur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    package org.speechmail.client.views;
     
    import java.io.IOException;
     
    import org.speechmail.client.MainApp;
     
    import javafx.fxml.FXML;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.layout.AnchorPane;
     
    public class RootLayoutController {
    	@FXML
    	private AnchorPane folderList;
     
    	@FXML
    	private AnchorPane messageList;
     
    	@FXML 
    	private AnchorPane messageViewer;
     
    	private MainApp mainApp;
     
    	public RootLayoutController() { }
     
        @FXML
        private void initialize() {
            FXMLLoader loader;
     
            try {
            	loader = new FXMLLoader(MainApp.class.getResource("views/fxml/FolderList.fxml"));
                this.folderList = (AnchorPane) loader.load();
     
                loader = new FXMLLoader(MainApp.class.getResource("views/fxml/FolderList.fxml"));
                this.messageList = (AnchorPane) loader.load();
     
                loader = new FXMLLoader(MainApp.class.getResource("views/fxml/FolderList.fxml"));
                this.messageViewer = (AnchorPane) loader.load();
     
            } catch (IOException e) {
            	e.printStackTrace();
            }
     
        }
     
        /**
         * Is called by the main application to give a reference back to itself.
         * 
         * @param mainApp
         */
        public void setMainApp(MainApp mainApp) {
            this.mainApp = mainApp;
     
     
        }
    }
    A l'initialisation du contrôleur, celui-ci charge les différents FXML et les affecte aux champs de type AnchorPane, qui sont "bindés" avec le FXML RootLayout.fxml

    Le problème, c'est que j'obtiens ma fenêtre principale, mais les sous-vues n'apparaissent pas.

    J'ai vérifié et elles sont bien chargées par le FXMLLoader mais je ne comprends pas pourquoi elles ne s'affichent pas dans la fenêtre.

    Je dois mal m'y prendre c'est sûr, mais en regardant la doc et les tutoriaux je ne trouve pas vraiment la solution.

    Merci d'avance.

  2. #2
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 840
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 840
    Points : 22 854
    Points
    22 854
    Billets dans le blog
    51
    Par défaut
    Il y a un soucis de compréhension / conception. Tu as des variables annotées @FXML ce qui sous-entend que l'inclusion s'effectue dans le FXML mais en fait tu les instancies dans le controlleur et tu oublies de les connecter a la scene / nœud manipulé par le contrôleur.

    Tu as deux manières de faire :

    1. Tes FXML secondaires sont référencés par ton FXML principal :
      Code XML : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      <BorderPane fx:id="rootPane" fx:controller="MyController" ...
          <center>
              <fx:include fx:id="centerPane" src="CenterPane.fxml"/>
          </center>
      </BorderPane>

      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      public class MyController implements Initializable {
          // Note : présence d'annotation , ce sont des variables injectées !
          @FXML
          private BorderPane rootPane;
          @FXML
          private Node centerPane;
          // Note : automatiquement on a accès au contrôleur avec <idDuFXMLSecondaire>+"Controller";
          @FXML
          private CenterController centerPaneController;
       
          @Override
          protected void inititialize(final URL url, final ResourceBundle bundle) {
              // On n'a pas besoin de charger les fichiers FXML manuellement.
              [...]
              // Mettre les listeners et co.
          }
      }
    2. Soit tu les charges dans ton contrôleur :
      Code XML : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      <BorderPane fx:id="rootPane" fx:controller="MyController" ...
      </BorderPane>

      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      public class MyController implements Initializable {
          @FXML
          private BorderPane rootPane;
          // Note : pas d'annotation, ce ne sont pas des variables injectées !
          private Node centerPane;
          private CenterController centerPaneController;
       
          @Override
          protected void inititialize(final URL url, final ResourceBundle bundle) {
              final FXMLLoader loader = new FXMLLoader(getClass().getResource("CenterPane.fxml"));
              centerPane = loader.load();
              centerPaneController = loader.getController();
              // Connexion au reste de la scène !
              // Sinon y a rien qui s'affiche.
              rootPane.setCenter(centerPane);
              [...]
              // Mettre les listeners et co.
          }
      }
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  3. #3
    Membre du Club
    Inscrit en
    Février 2005
    Messages
    242
    Détails du profil
    Informations personnelles :
    Âge : 32

    Informations forums :
    Inscription : Février 2005
    Messages : 242
    Points : 63
    Points
    63
    Par défaut
    Bonjour,

    J'ai opté pour la première solution, j'ai donc mis ça dans l'AnchorPane de mon SplitPane :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
      <children>
        <fx:include fx:id="folderList" src="FolderList.fxml" />
      </children>
    </AnchorPane>
    J'ai ajouté un binding dans mon contrôleur principal

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    public class RootLayoutController implements Initializable {
     
    	@FXML
    	private FolderListController folderList;
     
    ...
     
    }
    Et j'ai créé la classe pour le contrôleur FolderList :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    package org.speechmail.client.views;
     
    import java.net.URL;
    import java.util.ResourceBundle;
     
    import javafx.fxml.Initializable;
     
    public class FolderListController implements Initializable {
     
    	@Override
    	public void initialize(URL arg0, ResourceBundle arg1) {
    		// TODO Auto-generated method stub
     
    	}
     
    }
    J'obtiens l'erreur suivante à la compilation :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    javafx.fxml.LoadException: source is required.
    /C:/Users/Fabien/workspace/SpeechMail/target/classes/org/speechmail/client/views/fxml/RootLayout.fxml:38
     
    	at javafx.fxml.FXMLLoader.constructLoadException(Unknown Source)
    	at javafx.fxml.FXMLLoader.access$100(Unknown Source)
    	at javafx.fxml.FXMLLoader$IncludeElement.constructValue(Unknown Source)
    	at javafx.fxml.FXMLLoader$ValueElement.processStartElement(Unknown Source)
    	at javafx.fxml.FXMLLoader.processStartElement(Unknown Source)
    	at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
    	at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
    	at javafx.fxml.FXMLLoader.load(Unknown Source)
    	at org.speechmail.client.MainApp.initRootLayout(MainApp.java:44)
    	at org.speechmail.client.MainApp.start(MainApp.java:26)
    	at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(Unknown Source)
    	at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(Unknown Source)
    	at com.sun.javafx.application.PlatformImpl.lambda$null$173(Unknown Source)
    	at java.security.AccessController.doPrivileged(Native Method)
    	at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(Unknown Source)
    	at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(Unknown Source)
    	at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    	at com.sun.glass.ui.win.WinApplication.lambda$null$148(Unknown Source)
    	at java.lang.Thread.run(Unknown Source)
    Honnêtement, je ne comprends pas pourquoi Java essaie de chercher le FXML dans ce répertoire.

    Voici l'arborescence de mon projet :

    Nom : arbo.png
Affichages : 2222
Taille : 8,1 Ko

    Désolé, je suis vraiment à l'ouest, j'ai beaucoup de mal avec JavaFX, je m'exerce pour être un peu plus à l'aise pour l'instant j'ai beaucoup de mal, pourtant c'est pas faute de lire des tutos et la doc d'Oracle.

    Merci

  4. #4
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 840
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 840
    Points : 22 854
    Points
    22 854
    Billets dans le blog
    51
    Par défaut
    Oh c'est juste moi qui me suis planté car j'ai écrit trop vite. L'attribut à utiliser est source et non pas src.
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  5. #5
    Membre du Club
    Inscrit en
    Février 2005
    Messages
    242
    Détails du profil
    Informations personnelles :
    Âge : 32

    Informations forums :
    Inscription : Février 2005
    Messages : 242
    Points : 63
    Points
    63
    Par défaut
    Bonjour,

    Autant pour moi, j'aurais dû mieux regarder la doc pour <fx:include>.

    Par contre, en corrigeant j'ai toujours :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Caused by: java.lang.IllegalArgumentException: Can not set org.speechmail.client.views.FolderListController field org.speechmail.client.views.RootLayoutController.folderList to javafx.scene.layout.AnchorPane
    Donc j'ai remis les champs bindés FXML en type AnchorPane, comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public class RootLayoutController implements Initializable {
    	
    	@FXML
    	private AnchorPane folderList;
    	
    	@FXML
    	private AnchorPane messageList;
    	
    	@FXML 
    	private AnchorPane messageViewer;
    	
    	private MainApp mainApp;
    	
    	public RootLayoutController() { }
    
            [...]
    }
    Et là ça marche. Par contre si je veux connecter des contrôleurs à mes sous-vues, j'utilise fx:controller dans leurs fichiers FXML, c'est bien ça ?

    Merci d'avance.

  6. #6
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 840
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 840
    Points : 22 854
    Points
    22 854
    Billets dans le blog
    51
    Par défaut
    Oui

    Idem, si tu étais resté par un chargement par le code (comme tu le faisais au début) tu aurais pu injecter le contrôleur dans le loader au moment du chargement. J'utilise assez peu cette fonctionnalité et je renseigne généralement mes contrôleur directement dans le FXML.
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  7. #7
    Membre du Club
    Inscrit en
    Février 2005
    Messages
    242
    Détails du profil
    Informations personnelles :
    Âge : 32

    Informations forums :
    Inscription : Février 2005
    Messages : 242
    Points : 63
    Points
    63
    Par défaut
    Ok merci, dernière petite question, comment faire pour que chaque sous-parties prennent toute la place disponible dans les SplitPane, notamment lorsque je redimensionne la fenêtre principale ?

  8. #8
    Membre du Club
    Inscrit en
    Février 2005
    Messages
    242
    Détails du profil
    Informations personnelles :
    Âge : 32

    Informations forums :
    Inscription : Février 2005
    Messages : 242
    Points : 63
    Points
    63
    Par défaut
    Re-bonsoir,

    Autant pour moi, je n'avais pas cherché assez. J'ai enlevé les AnchorPane créés automatiquement par Scene Builder lorsque l'on pose un SplitPane, voici ma structure maintenant :

    Code XML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <BorderPane prefHeight="600.0" prefWidth="900.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.speechmail.client.views.RootLayoutController">
       <top>[...]</top>
       <center>
          <SplitPane dividerPositions="0.30" prefHeight="160.0" prefWidth="200.0" BorderPane.alignment="CENTER">
            <items>
              <fx:include fx:id="folderList" source="FolderList.fxml" />
              <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
                   <children>
                      <SplitPane dividerPositions="0.5" orientation="VERTICAL" prefHeight="200.0" prefWidth="160.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
                         <items>
                            <fx:include fx:id="messageList" source="MessageList.fxml" />
                            <fx:include fx:id="messageViewer" source="MessageViewer.fxml" />
                         </items>
                      </SplitPane>
                   </children>
                </AnchorPane>
            </items>
          </SplitPane>
       </center>
    </BorderPane>

    Mes sous-vues étant elles-mêmes contenus dans des AnchorPane, les ré-encapsuler dans d'autres AnchorPane n'avait pas beacoup de sens. Maintenant ça s'adapte parfaitement à la taille de la fenêtre.

    Et j'ai aussi enlevé les propriétés prefHeight et prefWidth sur les composants des sous-vues.

    Merci beaucoup pour l'aide en tout cas. Je marque résolu.

    A bientôt.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Stratégie pour une application avec plusieurs vues "empilées"
    Par camus3 dans le forum Windows Presentation Foundation
    Réponses: 6
    Dernier message: 20/12/2010, 15h15
  2. Une application, mais plusieurs processus
    Par tsing dans le forum Administration système
    Réponses: 5
    Dernier message: 04/12/2006, 17h15
  3. Réponses: 2
    Dernier message: 07/09/2006, 12h17
  4. Réponses: 5
    Dernier message: 25/04/2006, 14h13
  5. [MFC]Application avec plusieurs vues
    Par tus01 dans le forum MFC
    Réponses: 2
    Dernier message: 22/02/2006, 16h17

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo