Partage
  • Partager sur Facebook
  • Partager sur Twitter

Avoir un JMenu dynamique

Sujet résolu
    16 juillet 2019 à 13:41:52

    Bonjour à tous ! J'ai un souci qui m'ennuie depuis plusieurs jours et qui me bloque un peu dans mon travail !

    Dans le cadre de mes études je crée une application de gestion, pour ma part une gestion de concours. Lorsque j'ouvre mon appli je crée mon concours puis je peux ajouter des épreuves. Lorsque j'en ajoute une, elle se met dans une arrayList avec toutes les épreuves. Jusque là tout va bien. Le problème arrive au moment où je veux accéder aux concurrents d'une épreuve en particulier. Je vous laisse le code de mon JMenuBar et je vous explique !

    // Création de la barre de menu
    		JMenuBar menuoptions = new JMenuBar();
    		// Création d'un "bouton menu" Produit dans la barre de menu
    		JMenu menuAjouter = new JMenu("Ajouter une épreuve");
    		JMenuItem ajouter = new JMenuItem("Ajouter");
    		// Ajout de l'élément au menu
    		menuAjouter.add(ajouter);
    		ajouter.addActionListener(new ActionAjouter());
    		menuoptions.add(menuAjouter);
    		JMenu menuModifier = new JMenu("Modifier une épreuve");
    		// Création d'un élément du menu Produit
    		modifNom = new JMenuItem("Modifier le nom d'une épreuve");
    		// Ajout de l'élément au menu
    		menuModifier.add(modifNom);
    		modifNom.addActionListener(new ActionModifier());
    		// Création d'un deuxième élément du menu Produit
    		modifHoraire = new JMenuItem("Modifier l'horaire de départ d'une épreuve");
    		// Ajout de l'élément au menu
    		menuModifier.add(modifHoraire);
    		modifHoraire.addActionListener(new ActionModifier());
    		//Création d'un troisième élément
    		modifTerrain = new JMenuItem("Modifier le nom du terrain d'une épreuve");
    		// Ajout de l'élément au menu
    		menuModifier.add(modifTerrain);
    		modifTerrain.addActionListener(new ActionModifier());
    		menuoptions.add(menuModifier);
    		JMenu menuSuppr = new JMenu("Supprimer une épreuve");
    		JMenuItem supprimer = new JMenuItem("Supprimer");
    		// Ajout de l'élément au menu
    		menuSuppr.add(supprimer);
    		supprimer.addActionListener(new ActionSupprimer());
    		menuoptions.add(menuSuppr);
    		JMenu menuRecherche = new JMenu("Rechercher une épreuve");
    		JMenuItem rechercher = new JMenuItem("Rechercher");
    		// Ajout de l'élément au menu
    		menuRecherche.add(rechercher);
    		rechercher.addActionListener(new ActionRechercher());
    		menuoptions.add(menuRecherche);
    		if(lesEpreuves.size() != 0) {
    			menuConcurrents = new JMenu("Concurrents de l'épreuve");
    			for(Epreuve uneEpreuve:lesEpreuves) {
    				// Création d'un élément du menu
    				String nom = uneEpreuve.getNomEpreuve();
    				lesNoms.add(nom);
    				concurrents = new JMenuItem(nom);
    				concurrents.setName(nom);
    				// Ajout de l'élément au menu
    				menuConcurrents.add(concurrents);
    				concurrents.addActionListener(new ActionConcurrents());
    			}
    			menuoptions.add(menuConcurrents);
    		}
    		JMenu menuQuitter = new JMenu("Retour à la page d'accueil");
    		JMenuItem quitter = new JMenuItem("Retour");
    		// Ajout de l'élément au menu
    		menuQuitter.add(quitter);
    		// Ajout d'un listener appelant la classe menuActionQuitter lorsque l'on clique sur Quitter
    		quitter.addActionListener(new ActionQuitter());
    		// Ajout du menu dans la barre de menu
    		menuoptions.add(menuQuitter);
    		// Permet de définir le menu utilisé dans la JFrame
    		this.setJMenuBar(menuoptions);

    Le problème se trouve dans la boucle du JMenu des concurrents,je ne sais pas comment faire pour avoir une liste qui va me lister toutes les épreuves car ici ma boucle va retenir un seul élément du fait que c'est le JMenuItem concurrent qui va être le seul item utilisé... Du coup, si j'ai mis 6 épreuves dans mon concours, la liste va m'afficher les épreuves de ma liste mais lorsque je clique sur n'importe laquelle, il va sur la pagede la dernière uniquement. J'ai donc besoin de pouvoir savoir sur quelle épreuve j'ai cliqué pour accéder à la bonne épreuve par exemple avec un label ou un name mais j'ai essayé beaucoup, de choses, je n'ai pas réussi. Malheureusement je ne peux pas créer un item par epreuve puisque je ne peux pas connaitre à l'avance le nombre d'épreuves que je vais avoir dans mon concours... AIDEZ MOI :'( ^^'

    Je vous laisse également le code du ActionListener sur les épreuves, pour l'accès aux concurrents, le problème vient de la mémoire du nom de l'épreuve

    public class ActionConcurrents implements ActionListener{
    		public void actionPerformed(ActionEvent e) {
    			dispose();
    			Epreuve epreuve = null;
    			String nom = concurrents.getName();
    			int i = 0;
    			while(i < lesEpreuves.size() && !lesEpreuves.get(i).getNomEpreuve().equals(nom)) {
    				i = i + 1;
    			}
    			if(i < lesEpreuves.size()) {
    				epreuve = lesEpreuves.get(i);
    			}
    			new GererCouples(concours, epreuve).setVisible(true);
    			
    		}

    -
    Edité par AloïsZimmermann 16 juillet 2019 à 13:54:45

    • Partager sur Facebook
    • Partager sur Twitter
      16 juillet 2019 à 14:34:18

      D'abord, j'ai l'impression que tu as tendance à déclarer toutes tes variables dans ta classe principale.

      Par exemple on ne voit pas la déclaration de menuConcurrents, ni de lesNoms, ni de lesEpreuves, ni de concurrents.
      Toutes ces variables n'ont rien à faire dans la classe qui gère ton interface graphique. Tu devrais avoir une classe métier (je veux dire : centrée sur les traitements des données "métier", les données essentielles de ton appli) qui conserve ses données. Si une autre classe en a besoin, elle les lui demande.

      Si je te dis ça c'est non seulement pour t'apprendre une bonne pratique, mais aussi parce que cela t'aurait aiguillé vers la solution de ton problème.

      Actuellement, toutes tes instances ActionConcurrents sont exactement similaires. Elles n'ont pas d'attribut propre, donc aucune ne peut savoir à quelle épreuve elle est rattachée.

      Crée une variable d'instance de type Epreuve dans ta classe ActionConcurrents, que tu initialises par un constructeur (je ne vais pas tout t'écrire ;)). Tu les instancieras alors de cette façon :

      concurrents.addActionListener(new ActionConcurrents(uneEpreuve));

      NB : Au passage, j'aurais nommé la variable 'epreuve' plutôt que 'uneEpreuve'.

      -
      Edité par Zachee54 16 juillet 2019 à 14:39:26

      • Partager sur Facebook
      • Partager sur Twitter
        16 juillet 2019 à 15:06:37

        Zachee54 a écrit:

        D'abord, j'ai l'impression que tu as tendance à déclarer toutes tes variables dans ta classe principale.

        Par exemple on ne voit pas la déclaration de menuConcurrents, ni de lesNoms, ni de lesEpreuves, ni de concurrents.
        Toutes ces variables n'ont rien à faire dans la classe qui gère ton interface graphique. Tu devrais avoir une classe métier (je veux dire : centrée sur les traitements des données "métier", les données essentielles de ton appli) qui conserve ses données. Si une autre classe en a besoin, elle les lui demande.

        Si je te dis ça c'est non seulement pour t'apprendre une bonne pratique, mais aussi parce que cela t'aurait aiguillé vers la solution de ton problème.

        Actuellement, toutes tes instances ActionConcurrents sont exactement similaires. Elles n'ont pas d'attribut propre, donc aucune ne peut savoir à quelle épreuve elle est rattachée.

        Crée une variable d'instance de type Epreuve dans ta classe ActionConcurrents, que tu initialises par un constructeur (je ne vais pas tout t'écrire ;)). Tu les instancieras alors de cette façon :

        concurrents.addActionListener(new ActionConcurrents(uneEpreuve));

        NB : Au passage, j'aurais nommé la variable 'epreuve' plutôt que 'uneEpreuve'.

        -
        Edité par Zachee54 il y a 7 minutes


        merci de tes conseils ! si je déclare dans ma classe principale c'est parce que sinon je n'ai pas accès aux variables dans les actionListener ^^

        Après je ne comprends pas trop comment faire une classe métier... Aussi, si j'instancie mon épreuve comme tu as dit, je ne risque pas de ne plus être reliée à mes épreuves déjà présentes dans mon arrayList ?

        • Partager sur Facebook
        • Partager sur Twitter
          16 juillet 2019 à 15:58:45

          AloïsZimmermann a écrit:

          merci de tes conseils ! si je déclare dans ma classe principale c'est parce que sinon je n'ai pas accès aux variables dans les actionListener ^^

          Oui, c'est ce que font tous les débutants. On met toutes les variables en vrac pour les avoir partout sous la main.

          La force de la POO, c'est l'encapsulation.
          Chaque classe sert à une chose et une seule.
          Vu de l'extérieur, tu n'as pas besoin de (et à la rigueur tu ne dois pas) savoir comment la classe est codée. C'est son problème. Tu te sers de la classe pour les fonctionnalités qu'elle t'offre, un point c'est tout.
          Ca permet de changer complètement la façon de procéder de la classe le jour où tu en as besoin, sans impacter le reste de ton programme.

          AloïsZimmermann a écrit:

          Aussi, si j'instancie mon épreuve comme tu as dit, je ne risque pas de ne plus être reliée à mes épreuves déjà présentes dans mon arrayList ?

          Une fois que tu as créé tes menus et tes ActionConcurrents, tu peux oublier ta liste d'épreuves.
          Chaque instance ActionConcurrent retient uniquement l'objet Epreuve à laquelle elle est associée. La liste peut être détruite dans ta classe principale, ça ne détruit pas les épreuves pour autant.
          Un objet n'est détruit que lorsque plus aucun objet n'a de référence directe ou indirecte vers lui. Si tes ActionConcurrent ont une référence vers leur Epreuve, ils pourront toujours y accéder et c'est tout ce qui compte.

          AloïsZimmermann a écrit:

          Après je ne comprends pas trop comment faire une classe métier...

          Demande-toi ce qu'est une épreuve, ce qu'est un concours, ce qu'est un participant, un tableau de scores, etc.
          Découpe ton problème en notions élémentaires, demande-toi de quelles informations tu as besoin à propos d'une épreuve (un objectif, un barème ?), de quoi tu as besoin pour un concours (une liste d'épreuves et de participants, éventuellement les points des participants ?), un participant (un nom, une adresse électronique, un palmarès ?).
          Ensuite tu crées une classe pour chaque notion. La classe doit donner les infos sur la notion qu'elle gère, et uniquement ça.

          Ensuite, si la liste des épreuves est par exemple dans la classe Concours, tu ne dois avoir aucune liste d'épreuves ailleurs. Si tu as besoin de la liste des épreuves, tu gardes en mémoire uniquement l'objet Concours et tu la lui demandes quand tu en as besoin.

          Quant à ta classe qui gère l'interface... ce n'est pas une classe métier, c'est juste une vue. Elle a seulement besoin que tu lui donnes des informations à afficher. Tu peux très bien passer une instance Concours à la méthode chargée d'initialiser la fenêtre. Elle s'en sert pour connaître la liste des épreuves à afficher dans le menu, et ensuite elle l'oublie : elle n'en a plus besoin.
          Tu peux même avoir une méthode updateEpreuves(Concours) qui supprime tous tes JMenuItem et les recrée à partir d'un nouvel objet Concours, si ta liste d'épreuves est amenée à changer avec le temps.

          Je te conseille les deux premières parties du cours Programmez en orienté objet avec PHP. C'est pour le PHP, évidemment, mais il est bien fait et c'est totalement transposable en Java et il aborde mieux les questions de conception (c'est mon point de vue). La 3ème partie, par contre, est spécifique au PHP.

          Ensuite, c'est la pratique qui aide. On apprend les design patterns, les principes SOLID... Le livre "Clean code" de Robert C. Martin se lit facilement et c'est une vraie bible dans ce domaine. Il existe aussi en français.

          • Partager sur Facebook
          • Partager sur Twitter
            17 juillet 2019 à 11:13:39

            Zachee54 a écrit:

            AloïsZimmermann a écrit:

            merci de tes conseils ! si je déclare dans ma classe principale c'est parce que sinon je n'ai pas accès aux variables dans les actionListener ^^

            Oui, c'est ce que font tous les débutants. On met toutes les variables en vrac pour les avoir partout sous la main.

            La force de la POO, c'est l'encapsulation.
            Chaque classe sert à une chose et une seule.
            Vu de l'extérieur, tu n'as pas besoin de (et à la rigueur tu ne dois pas) savoir comment la classe est codée. C'est son problème. Tu te sers de la classe pour les fonctionnalités qu'elle t'offre, un point c'est tout.
            Ca permet de changer complètement la façon de procéder de la classe le jour où tu en as besoin, sans impacter le reste de ton programme.

            AloïsZimmermann a écrit:

            Aussi, si j'instancie mon épreuve comme tu as dit, je ne risque pas de ne plus être reliée à mes épreuves déjà présentes dans mon arrayList ?

            Une fois que tu as créé tes menus et tes ActionConcurrents, tu peux oublier ta liste d'épreuves.
            Chaque instance ActionConcurrent retient uniquement l'objet Epreuve à laquelle elle est associée. La liste peut être détruite dans ta classe principale, ça ne détruit pas les épreuves pour autant.
            Un objet n'est détruit que lorsque plus aucun objet n'a de référence directe ou indirecte vers lui. Si tes ActionConcurrent ont une référence vers leur Epreuve, ils pourront toujours y accéder et c'est tout ce qui compte.

            AloïsZimmermann a écrit:

            Après je ne comprends pas trop comment faire une classe métier...

            Demande-toi ce qu'est une épreuve, ce qu'est un concours, ce qu'est un participant, un tableau de scores, etc.
            Découpe ton problème en notions élémentaires, demande-toi de quelles informations tu as besoin à propos d'une épreuve (un objectif, un barème ?), de quoi tu as besoin pour un concours (une liste d'épreuves et de participants, éventuellement les points des participants ?), un participant (un nom, une adresse électronique, un palmarès ?).
            Ensuite tu crées une classe pour chaque notion. La classe doit donner les infos sur la notion qu'elle gère, et uniquement ça.

            Ensuite, si la liste des épreuves est par exemple dans la classe Concours, tu ne dois avoir aucune liste d'épreuves ailleurs. Si tu as besoin de la liste des épreuves, tu gardes en mémoire uniquement l'objet Concours et tu la lui demandes quand tu en as besoin.

            Quant à ta classe qui gère l'interface... ce n'est pas une classe métier, c'est juste une vue. Elle a seulement besoin que tu lui donnes des informations à afficher. Tu peux très bien passer une instance Concours à la méthode chargée d'initialiser la fenêtre. Elle s'en sert pour connaître la liste des épreuves à afficher dans le menu, et ensuite elle l'oublie : elle n'en a plus besoin.
            Tu peux même avoir une méthode updateEpreuves(Concours) qui supprime tous tes JMenuItem et les recrée à partir d'un nouvel objet Concours, si ta liste d'épreuves est amenée à changer avec le temps.

            Je te conseille les deux premières parties du cours Programmez en orienté objet avec PHP. C'est pour le PHP, évidemment, mais il est bien fait et c'est totalement transposable en Java et il aborde mieux les questions de conception (c'est mon point de vue). La 3ème partie, par contre, est spécifique au PHP.

            Ensuite, c'est la pratique qui aide. On apprend les design patterns, les principes SOLID... Le livre "Clean code" de Robert C. Martin se lit facilement et c'est une vraie bible dans ce domaine. Il existe aussi en français.


            eh bah on peut dire que c'est une réponse claire et complète ! :D

            Effectivement j'ai déjà des classes métier ça m'était sorti de la tête, j'ai épreuve, couple et concours.

            Merci beaucoup pour tous ces conseils, je ne suisqu'à 1 année d'informatique, j'ai encore énormément de choses à apprendre ! Cela fonctionne et c'est très libérateur après tant d'heures de galères ^^

            Merci Merci Merciii !

            Mais puis-je utiliser vos services une dernière fois ? Car mon JTable de mes épreuves n'affiche que 1 ligne sur 2, l'autre est complètement blanche et j'ignore à quoi cela est dû :/

            Voici le code de mon tableau (qui s'adapte en fonction de la discipline):

            int taille = lesEpreuves.size();
            		if(taille > 0) {
            			if(discipline.equals("CCE")) {
            				Object data[][]= new Object[taille][11];
            				//parcours de la collection et remplissage du tableau
            				for (int i = 0 ; i < lesEpreuves.size() ; i++){
            					Cce uneEpreuve = (Cce) lesEpreuves.get(i);
            					data[i][0] = uneEpreuve.getNomEpreuve();
            					data[i][1]= uneEpreuve.getEngagesMax();
            					data[i][2]= uneEpreuve.getTarif();
            					data[i][3]= uneEpreuve.getHoraireDress();
            					data[i][4]= uneEpreuve.getTerrainDress();
            					data[i][5]= uneEpreuve.getHoraireSaut();
            					data[i][6]= uneEpreuve.getTerrainSaut();
            					data[i][7]= uneEpreuve.getHauteurSaut();
            					data[i][8]= uneEpreuve.getHoraireCross();
            					data[i][9]= uneEpreuve.getTerrainCross();
            					data[i][10]= uneEpreuve.getHauteurCross();
            					i++;
            				}
            				String [] title = {"Nom de l'épreuve", "Nombres d'engagés maximum", "Tarif de l'épreuve", "Horaire de début du dressage", "Terrain du dressage", "Horaire de début de l'hippique", "Terrain de l'hippique", "Hauteur de l'hippique", "Horaire de début du cross", "Terrain du cross", "Hauteur du cross"};
            				this.tableau = new JTable(data,title){
            					public boolean isCellEditable(int row, int col) {
            						return false;
            					}
            				};
            			}
            			else {
            				Object data[][]= new Object[taille][6];
            				if(discipline.equals("CSO")) {
            					//parcours de la collection et remplissage du tableau
            					for (int i = 0 ; i < lesEpreuves.size() ; i++){
            						Cso uneEpreuve = (Cso) lesEpreuves.get(i);
            						data[i][0] = uneEpreuve.getNomEpreuve();
            						data[i][1]= uneEpreuve.getEngagesMax();
            						data[i][2]= uneEpreuve.getTarif();
            						data[i][3]= uneEpreuve.getHoraireDebut();
            						data[i][4]= uneEpreuve.getHauteur();
            						data[i][5]= uneEpreuve.getNomTerrain();
            						i++;
            					}
            					String [] title = {"Nom de l'épreuve", "Nombres d'engagés maximum", "Tarif de l'épreuve", "Horaire de début d'épreuve", "Hauteur de l'épreuve", "Nom du terrain de l'épreuve"};
            					this.tableau = new JTable(data,title){
            						public boolean isCellEditable(int row, int col) {
            							return false;
            						}
            					};
            				}
            				else {
            					//parcours de la collection et remplissage du tableau
            					for (int i = 0 ; i < lesEpreuves.size() ; i++){
            						Dressage uneEpreuve = (Dressage) lesEpreuves.get(i);
            						data[i][0] = uneEpreuve.getNomEpreuve();
            						data[i][1]= uneEpreuve.getEngagesMax();
            						data[i][2]= uneEpreuve.getTarif();
            						data[i][3]= uneEpreuve.getHoraireDebut();
            						data[i][4]= uneEpreuve.getNomTerrain();
            						data[i][5]= uneEpreuve.getSponsor();
            						i++;
            					}
            					String [] title = {"Nom de l'épreuve", "Nombres d'engagés maximum", "Tarif de l'épreuve", "Horaire de début d'épreuve", "Nom du terrain de l'épreuve", "Sponsor du concours"};
            					this.tableau = new JTable(data,title){
            						public boolean isCellEditable(int row, int col) {
            							return false;
            						}
            					};
            				}
            			}
            	
            			this.tableau.getTableHeader().setReorderingAllowed(false);
            			this.tableau.getTableHeader().setResizingAllowed(false);
            			this.tableau.setRowHeight(30); //espacement des cellules
            			// le tableau doit être obligatoirement ajouté dans un composant JScrollPane
            			this.scrollPane = new JScrollPane(this.tableau);
            		}

            -
            Edité par AloïsZimmermann 17 juillet 2019 à 11:47:19

            • Partager sur Facebook
            • Partager sur Twitter
              17 juillet 2019 à 17:42:12

              for (int i = 0 ; i < lesEpreuves.size() ; i++){
                ...
                i++;
              }

              Tu écris deux fois i++. Donc i est incrémenté de 2 à chaque boucle. Il suffit de l'écrire dans le for.

              Pour le contenu des tables, crée plutôt une classe qui servira de modèle pour ta table en implémentant l'interface TableModel ou en étandant AbstractModel.
              Tu crées autant de classes que de types de tables que tu veux dans ton application (1 présentation = 1 modèle).

              C'est d'autant plus nécessaire ici que tu es obligé de faire un héritage de la classe JTable pour réécrire la méthode isCellEditable. Cette méthode fait appel au modèle de table, il suffit donc que la méthode isCellEditable retourne false dans le modèle que tu auras créé.

              • Partager sur Facebook
              • Partager sur Twitter

              Avoir un JMenu dynamique

              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
              • Editeur
              • Markdown