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 et applications multi-fenêtres


Sujet :

JavaFX

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2012
    Messages : 91
    Par défaut JavaFX et applications multi-fenêtres
    Salut !
    Je suis débutant en JavaFX et j'aimerais réaliser une application multi-fenêtres avec base de données en m'appuyant sur JavaFX. Je crois que c'est un bon exercice pour appréhender (tous) les niveaux usuels et basiques de la programmation avec JavaFX.
    Ma démarche est la suivante :
    - Avec SceneBuilder 1.0 x64, je crée mes vues.
    - Puisque j'ai plusieurs vues, je crée plusieurs controllers
    - Puisque tous les controllers ont des lignes de code en commun (la partie de l'instanciation de la vue dans la méthode start par exemple), je crée une classe abstraite contenant toutes ces lignes de code avec des paramètres et je fais que chacun de mes controllers étende cette classe abstraite
    - Je crée une classe principale pour mon projet (contenant la méthode main pour le démarrage de l'application). Dans le main, j'instancie un controller pour ma vue qui sert de menu et je l'affiche.
    - Sous chaque item de mon menu, j'instancie un controller pour la vue concernée et je l'affiche.

    De prime abord, ça devrait être exact (c'est ce que je pensais en tout cas). Seulement, cette démarche donne des résultats pas terribles :
    1. chaque vue est affichée avec un bouton séparé dans la barre des tâches
    2. puisque les vues sont séparées, je n'arrive pas à les afficher en fenêtre modale
    3. quand j'instancie un controller, il est à une adresse mémoire X mais quand je fais une action sur la vue de ce controller, je constate que le controller qui réagit est à une autre adresse Y, pourtant je n'instancie qu'une fois.

    Toutes ces imperfections me laissent un goût amer d'échec à la bouche.
    J'aimerais donc savoir si je procède comme il faut, et obtenir, si possible, des liens pour me permettre de corriger tout ça.

    Merci d'avoir lu ce (long) récit de ma préoccupation et merci pour vos interventions...

  2. #2
    Rédacteur/Modérateur

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

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

    Informations forums :
    Inscription : Août 2005
    Messages : 6 900
    Billets dans le blog
    54
    Par défaut
    Salut, il est difficile de te répondre sans un minimum de code qui démontre le problème.
    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
    Nouveau candidat au Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2012
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2012
    Messages : 3
    Par défaut
    Citation Envoyé par Fandyz Voir le message
    Salut !

    3. quand j'instancie un controller, il est à une adresse mémoire X mais quand je fais une action sur la vue de ce controller, je constate que le controller qui réagit est à une autre adresse Y, pourtant je n'instancie qu'une fois.
    Si la classe de controle est spécifiée dans le fichier FXML (au moyen de fx:controller) alors FXMLLoader.load() instancie la classe et utilise cette instance. Il ignore silencieusement l'instance spécifiée par FXMLLoader.setController().

    Si la classe de controle n'est pas spécifiée dans le fichier FXML, alors
    FXMLLoader.load() utilise l'instance spécifiée par FXMLLoader.setController().

    Avec ce design, on peut facilement avoir deux instances de classe de controle
    mais une seule étant utilisée par JavaFX. A vérifier.

  4. #4
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2012
    Messages : 91
    Par défaut
    Salut !
    Ma classe abstraite se présente 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
    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
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    public abstract class ViewsAbstractClass implements Initializable{
     
        private String FXMLRessource;
        private String titreFenetre;
        private Parent root;
        private Stage stage;
        private Scene scene;
     
        public ViewsAbstractClass() {
        }
     
        public ViewsAbstractClass(String cheminFXML, String titreFenetre) {
            if (cheminFXML != null && !cheminFXML.equals("")) {
                this.FXMLRessource = cheminFXML;
            }
     
            if (titreFenetre != null && !titreFenetre.equals("")) {
                this.titreFenetre = titreFenetre;
            }
     
            createView();
        }
     
        @Override
        public void initialize(URL url, ResourceBundle rb) {
     
        }
     
        private void createView(){
            try {
                if (getClass().getResource(this.FXMLRessource) == null){
                    throw new Exception();
                }
     
                this.root = FXMLLoader.load(getClass().getResource(this.FXMLRessource));
                this.scene = new Scene(this.root);
     
                this.stage = new Stage();
                this.stage.setScene(this.scene);
                this.stage.setTitle(titreFenetre);
                this.stage.centerOnScreen();
                this.stage.setResizable(false);
            } catch (Exception ex) {
                System.out.println(ex.toString());
                JOptionPane.showMessageDialog(null, "Erreur de chargement de la fenêtre : fichier inconnu.", "Erreur", JOptionPane.ERROR_MESSAGE);
            }
        }
     
        public void show() {
            this.stage.show();
        }
     
        public void show(String cheminFXML, String titreFenetre) {
            this.FXMLRessource = cheminFXML;
     
            this.titreFenetre = titreFenetre;
     
            createView();
     
            this.show();
        }
     
        public void close(){
            //this.scene.getWindow().hide();
            this.stage.close();
        }
     
        public void setResizable(Boolean resizable){
            this.stage.setResizable(resizable);
        }
    J'ai par exemple une fenêtre Connexion déclarée ainsi :
    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
    <AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="242.0" prefWidth="482.0" xmlns:fx="http://javafx.com/fxml" fx:controller="ConnexionController">
      <children>
        <ImageView fx:id="imImage" fitHeight="92.0" fitWidth="122.66666666666666" layoutX="32.0" layoutY="75.0" pickOnBounds="true" preserveRatio="true">
          <image>
            <Image url="@images/users.png" preserveRatio="false" smooth="false" />
          </image>
        </ImageView>
        <Label layoutX="148.0" layoutY="75.0" text="Nom d'utilisateur :" />
        <Label layoutX="163.0" layoutY="113.0" text="Mot de passe :" />
        <TextField id="tfUserName" fx:id="tfUserName" layoutX="257.0" layoutY="72.0" prefWidth="200.0" />
        <PasswordField fx:id="pwfPassWord" layoutX="257.0" layoutY="118.0" prefWidth="200.0" />
        <Button fx:id="btConnection" layoutX="257.0" layoutY="157.0" mnemonicParsing="false" onAction="#btConnectionAction" text="Connexion" />
        <Button fx:id="btCancel" layoutX="378.0" layoutY="157.0" mnemonicParsing="false" onAction="#btCancelAction" prefWidth="77.0" text="Annuler" />
        <Label id="lPasswordForgotten" fx:id="lRecoverPassword" layoutX="340.0" layoutY="209.0" text="Mot de passe oublié ?" />
      </children>
    </AnchorPane>
    et elle est reliée à ce controller :
    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
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    public class ConnexionController extends ViewsAbstractClass{
     
        @FXML
        TextField tfUserName;
     
        @FXML
        PasswordField pwfPassWord;
     
        @FXML
        Button btConnexion;
     
        @FXML
        Button btCancel;
     
        @FXML
        Label lRecoverPassword;
     
        private Utilisateur utilisateur;
        private MenuPrincipalController menuPrincipal;
     
        public void btCancelAction() {
    //        this.close();
            JOptionPane.showMessageDialog(null, "cancel button clicked : connexion = " + this);
        }
     
        public void btConnectionAction() {
            JOptionPane.showMessageDialog(null, "validate button clicked 1 : connexion = " + this);
            makeConnection();
            JOptionPane.showMessageDialog(null, "validate button clicked 2 : connexion = " + this);
        }
     
        public ConnexionController() {
        }
     
        public ConnexionController(String cheminFXML, String titreFenetre) {
            super(cheminFXML, titreFenetre);
        }
     
        public ConnexionController(String cheminFXML, String titreFenetre, MenuPrincipalController menuPrincipal) {
            super(cheminFXML, titreFenetre);
            this.menuPrincipal = menuPrincipal;
        }
     
        public void connectionHolded(){
            tfUserName.setDisable(true);
        }
     
        public void showed(){
            //pwfPassWord.clear();
            JOptionPane.showMessageDialog(null, "shown : connexion = " + this);
            super.show();
        }
     
        public void makeConnection(){
            JOptionPane.showMessageDialog(null, "make connexion 1 : connexion = " + this);
            if (recuperationUtilisateur() == null){
                methods.defaultMessages(GenericMethods.erreur, "Le nom d'utilisateur ou le mot de passe est incorrect, connexion impossible.");
            }
            else{
                JOptionPane.showMessageDialog(null, "validation : connexion = " + this);
                this.menuPrincipal.connectionMaked();
            }
            JOptionPane.showMessageDialog(null, "make connexion 2 : connexion = " + this);
        }
     
        public MenuPrincipalController getMenuPrincipal() {
            return menuPrincipal;
        }
     
        public void setMenuPrincipal(MenuPrincipalController menuPrincipal) {
            this.menuPrincipal = menuPrincipal;
        }
     
        public Utilisateur getUtilisateur() {
            return utilisateur;
        }
     
        public void setUtilisateur(Utilisateur utilisateur) {
            this.utilisateur = utilisateur;
        }
    }
    J'ai mis beaucoup de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    JOptionPane.showMessageDialog()
    pour "tracer" mon code et les résultats ne sont pas très intéressent :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    shown : connexion = ConnexionController@7c8323a3
    validate button clicked 1 : connexion = ConnexionController@75f5d3de
    make connexion 1 : connexion = ConnexionController@75f5d3de
    make connexion 2 : connexion = ConnexionController@75f5d3de
    validate button clicked 2 : connexion = ConnexionController@75f5d3de
    Je n'ai vraiment aucune idée du problème. Pourtant je doit agir sur le menu principal. Du coup, j'ai un NullPointerException parce que la deuxième instance n'a pas de menu principal !

  5. #5
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2012
    Messages : 91
    Par défaut
    Citation Envoyé par eleponner Voir le message
    Si la classe de controle est spécifiée dans le fichier FXML (au moyen de fx:controller) alors FXMLLoader.load() instancie la classe et utilise cette instance. Il ignore silencieusement l'instance spécifiée par FXMLLoader.setController().

    Si la classe de controle n'est pas spécifiée dans le fichier FXML, alors
    FXMLLoader.load() utilise l'instance spécifiée par FXMLLoader.setController().

    Avec ce design, on peut facilement avoir deux instances de classe de controle
    mais une seule étant utilisée par JavaFX. A vérifier.
    Merci eleponner mais, à vrai dire, j'ai rien compris

  6. #6
    Rédacteur/Modérateur

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

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

    Informations forums :
    Inscription : Août 2005
    Messages : 6 900
    Billets dans le blog
    54
    Par défaut
    Bon alors reprenons depuis le debut...

    Citation Envoyé par Fandyz Voir le message
    Salut !
    - Avec SceneBuilder 1.0 x64, je crée mes vues.
    ok

    - Puisque j'ai plusieurs vues, je crée plusieurs controllers
    ok

    - Puisque tous les controllers ont des lignes de code en commun (la partie de l'instanciation de la vue dans la méthode start par exemple), je crée une classe abstraite contenant toutes ces lignes de code avec des paramètres et je fais que chacun de mes controllers étende cette classe abstraite
    ok, pourquoi pas, bonne idée.

    - Je crée une classe principale pour mon projet (contenant la méthode main pour le démarrage de l'application). Dans le main, j'instancie un controller pour ma vue qui sert de menu et je l'affiche.
    ok

    - Sous chaque item de mon menu, j'instancie un controller pour la vue concernée et je l'affiche.

    [...]

    3. quand j'instancie un controller, il est à une adresse mémoire X mais quand je fais une action sur la vue de ce controller, je constate que le controller qui réagit est à une autre adresse Y, pourtant je n'instancie qu'une fois.

    Normalement, puisque tu as specifie ton controller dans ton FXML tu dois :
    1. Charger le noeud via le FXMLLoader.
    2. Récupérer le contrôleur via le FXMLLoader.


    Or pour ce que je vois la tu:
    1. Instancie un contrôleur
    2. Charge le noeud via le FXMLLoader


    Et donc c'est normal que tu ais deux contrôleur, un qui soit vide (pas lie au noeud) et un second qui soit détaché et gère le noeud.

    1. chaque vue est affichée avec un bouton séparé dans la barre des tâches

    2. puisque les vues sont séparées, je n'arrive pas à les afficher en fenêtre modale
    Tes fenêtres ne sont pas liées entre elles. Il faut appeler stage.initOwner() avec la valeur qui va bien (le stage parent) pour les attacher ensemble.
    Tu peux également jouer sur la modalité et le style du stage (palette).

    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
        public static Pair<AnchorPane, ? extends ViewsAbstractClass> createView(Stage parent, String name) {
            Pair<AnchorPane, ? extends ViewsAbstractClass> result = null;
            try {
                URL fxmlURL = ViewsAbstractClass.class.getResource(name + ".fxml");
                if (fxmlURL == null) {
                    throw new Exception();
                }
                FXMLLoader fxmlLoader = new FXMLLoader(fxmlURL);
                AnchorPane root = (AnchorPane) fxmlLoader.load();
                ViewsAbstractClass controller = (ViewsAbstractClass) fxmlLoader.getController();
                result = new Pair(root, controller);
                Scene scene = new Scene(root);
                Stage stage = new Stage();
                stage.initOwner(parent);
    //            stage.initModality(Modality.APPLICATION_MODAL);
    //            stage.initStyle(StageStyle.UTILITY);
                stage.setScene(scene);
                stage.setTitle(controller.titreFenetre);
                stage.centerOnScreen();
                stage.setResizable(false);
            } catch (Exception ex) {
                System.out.println(ex.toString());
                JOptionPane.showMessageDialog(null, "Erreur de chargement de la fenêtre : fichier inconnu.", "Erreur", JOptionPane.ERROR_MESSAGE);
            }
            return result;
        }
    T'as pas besoin de stocker la scène ou le stage dans tes contrôleurs, il te suffit de faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <AnchorPane id="AnchorPane" fx:id="rootPane" [...]
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    @FXML
    private AnchorPane rootPane;
     
    Scene scene = rootPane.getScene();
    Stage stage = (Stage)rootPane.getScene().getWindow();
    Idem avec n'importe quel autre composant nommé.
    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 confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2012
    Messages : 91
    Par défaut
    J'ai trouvé des solutions à certaines de mes préoccupations.
    En fait, il fallait instancier un fichier FXMLLoader pour chaque controller; grâce à cela, je peux passer des données entre fenêtres et agir sur d'autres fenêtres. Merci bouye de l'avoir mentionné

    Je parviens aussi à rendre mes fiches modale grâce au
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    stage.initModality(Modality.APPLICATION_MODAL);
    Merci encore bouye

    Mais pour désactiver les boutons de chaque fenêtre de la barre des tâches, c'est la même galère. . J'ai ajouter un attribut à ma classe abstraite pour que tous les controllers aient le même parent et j'ajoute
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    private void createView(){
      try{
        /* ... */
        stage.initOwner(parent);
        /* ... */
      } catch(...){
      /* ... */
      }
    }
    Ensuite, avant d'instancier le controller de la classe principale, je définit la valeur de l'attribut parent de la classe abstraite:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public void start(Stage stage) throws Exception {
      ViewsAbstractClass.setParent(stage);
      /* ... */
    }
    Mais ça n'a pas l'air de suffire; ou peut-être que je le fais mal.

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 14/06/2010, 16h24
  2. conseils pour une application multi-fenêtres
    Par p1xl_01 dans le forum C#
    Réponses: 14
    Dernier message: 25/05/2010, 15h29
  3. Application multi fenêtrée jsf/richfaces
    Par barzane dans le forum JSF
    Réponses: 16
    Dernier message: 02/10/2009, 17h14
  4. [Lazarus] Application multi-fenêtrée
    Par azertyuiopqsdfghjkl dans le forum Lazarus
    Réponses: 3
    Dernier message: 09/06/2009, 07h05
  5. Application multi-fenêtrée
    Par evilnet dans le forum AWT/Swing
    Réponses: 6
    Dernier message: 06/04/2007, 20h39

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