IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Téléchargé 3 fois
Vote des utilisateurs
0 
0 
Détails
Licence : Non renseignée
Mise en ligne le 29 mai 2022
Langue : Français
Référencé dans
Navigation

JMenu : ActionListener unique pour toutes les items d'un menu, et lance le traitement voulu pour chacune.

Après plusieurs recherches et échanges, je n'ai pas trouvé une manière efficace pour gérer les déclenchements sur une JMenuItem de manière concise.
En effet, on conseille de faire pour chaque item, un ActionListener spécifique à cette item, qui fera le traitement voulu.
L’inconvénient est que le code se répète, presque identique pour chaque JMenuItem, et cela devient lourd et difficilement lisible pour moi...
C'est le cas du premier menu de ma source, le menu "fichier", pas élégant et peu engageant à décoder.


Après du temps et des essais, j'ai préféré utiliser le membre natif "name", de chaque JMenuItem, pour identifier de manière unique chaque item.
Après déclenchement par un clic sur une JMenuItem, je recherche l'objet source du déclenchement, je le caste en JMenuItem, et je peux en lire la valeur du membre "name" : String nom = ((JMenuItem) e.getSource()).getName();
L'item est identifié et on peut démarrer le traitement spécifique voulu sur cette item.
C'est le cas du menu "Edition" de la source proposée.
L'avantage est que le "ActionListener" est le même pour toutes les items du menu et pourtant, le lancement de l'action reste spécifique à l'item cliquée.


Autre approche possible non fournie ici : on peut identifier la JMenuItem, à l'aide d'un entier.
Pour cela je vois deux solutions :

1/ On analyse la chaine du membre "name" et on l’interprète comme un integer :
String i = ((JMenuItem) e.getSource()).getName();
int k = Integer.parseInt (i);

2/ on Créé sa propre classe MesJMenuItem par exemple, qui étendent les JMenuItem natives, et on leur ajoute un membre : "int numItem = 12", par exemple, et on détecte alors ce membre dans le ActionListener unique pour lancer les traitements spécifiques.


Voila, n'ayant pas trouvé cela clairement, je vous propose ces idées, car pour moi, je trouve qu'un ActionListener unique pour toutes les JMenusItems, est plus clair et allège mes menus.

N'hésitez pas à me donner vos avis, même s'ils sont critiques bien sur!....
Avatar de gervais.b
Membre averti https://www.developpez.com
Le 29/05/2022 à 21:23
Comme je vous le disait de le post initial, l'utilisation la plus courante est d'avoir des sous classes de Action. C'est d'ailleurs l'approche proposée par Oracle dans les tutoriels Swing: https://docs.oracle.com/javase/tutor...sc/action.html

Les avantages sont:
+ Un typage fort. Le refactoring est facile car votre Ide peut identifier les utilisations de la classe (Contrairement à une solution basée sur des String ou les erreurs de typos sont faciles)
+ Une clareté du code. Une new JMenuItem(new SetColorAction(Color.BLUE, selection)) me semble plus claire que new JMenuItem("Blue", new MultiAction())
+ Une action est réutilisable et cohérente. Si je change l'icône de l'action, tous les boutons et menus qui l'utilisent seront mis à jour.

Les désavantages:
+ C'est verbeux (à vérifier*)
+ Ca ne vous convient pas.

Je cois que la solution réside dans le dernier désavantage: "Ca ne vous convient pas".
Java est un langage très large, qui permet de faire beaucoup de choses et qui n'impose pas trop de contraintes. C'est une faiblesse mais aussi une force. Au vu du décalage entre votre première question et celle-ci, il est clair que vous avez pris le temps de réfléchir et de chercher la solution qui vous convient le mieux. Gardez alors celle qui vous convient. L'essentiel étant, de faire ce qui vous semble le mieux car c'est vous qui travaillez sur ce projet et c'est vous qui le connaissez le mieux.

Ce que vous pourriez-faire c'est vous poser la question de comment améliorer les choses. Vous pourriez peut-être utiliser une enum pour tous les noms d'actions, ça simplifierais le réfactoring et limiterais les erreurs de typos. Peut-être même créer une JMenuItem qui n'attends en paramètre qu'une seule valeur de l'enum (ou plusieurs si ce menu doit faire plusieurs actions en une) et/ou créer vos menus sur base de cette enum via une boucle qui crée un item pour chaque valeur de l'enum (ca ne fonctionneras pas pour les sous menu car un enum n'est pas hierachique).

Le name à d'autres utilités. Par contre la clef/constante https://docs.oracle.com/javase/8/doc...ON_COMMAND_KEY est souvent utilisée pour identifier l'action.

Vous pourriez aussi aller plus loin et faire de votre ActionListener unique le centre de votre application, un peu comme ce que l'on trouve dans le web avec Redux qui centralise les actions tout en séparant une action de ces effets.

----

* On peut créer des sous classes pour limiter la répétition, les détails du comportement sont alors définis par les paramètres du constructeur. new SetColorAction(Color.BLUE); new SetColorAction(Color.RED); ..
Est-ce que la suite de if("SetColorToBlue".equals(menu.getName()) est vraiment plus lisible, moins verbeuse et risqué que quelques classes ?
Avec plusieurs actions, vous pouvez simplifiez votre code:

Code : Sélectionner tout
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
// Avant, tout est défini dans le menu
JMenuItem menuOpenFile = new JMenuItem("Open File ...");
menuOpenFile.setIcon(new ImageIcon("icones/open.png"));
menuOpenFile.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        MyWindow.affichage.append("on a déclenché le listener spécifique à  l'item :         Open File \n");
    }
});
menuFile.add(menuOpenFile);

// Après, l'action définit son comportement mais aussi son nom, icone.
// -- OpenFileAction.java
class OpenFileAction extends AbstractAction {

    public OpenFileAction() {
        super("Open File ...", new ImageIcon("icones/open.png"));
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        MyWindow.affichage.append("on a déclenché le listener spécifique à  l'item :         Open File \n");
    }
}

// -- CreateJMenuBar.java
menuFile.add(new OpenFileAction());
Personellement, je défini comme vous une sous classe de JMenuBar mais je découpe la création des menus dans différentes méthodes ou via des sous classes de JMenu quand le menu est particulier.
Avatar de patdu26
Membre habitué https://www.developpez.com
Le 30/05/2022 à 15:36
bonjour gervais.b,

merci tout d'abord pour la remise en forme de mon message et pour le temps passé pour votre analyse et tous ces nouveaux éléments.

J'ai passé pas mal de temps à tenter des choses dans mes menus, car c'est vrai qu'un listener à la volée, pour chaque item, ça me perturbe...(j'ai un cerveau de post-cinquantenaire, et donc, une approche personnelle un peu rigide, difficile à modifier)

Votre vision me permet d'avancer peu à peu, mais plus j'en découvre et que j'ai l'impression d’améliorer certaines spécificités, plus je ressens que les possibilités peuvent s'étendre au-delà, sans pour autant en avoir la maitrise pour le moment, mais c'est aussi cela qui est intéressant...

Encore merci et peut-être à bientôt pour de nouvelles difficultés à évoquer..
Avatar de gervais.b
Membre averti https://www.developpez.com
Le 30/05/2022 à 17:07
Citation Envoyé par patdu26 Voir le message
car c'est vrai qu'un listener à la volée, pour chaque item, ça me perturbe...
C'est peut-être ça le problème. Ne voyez pas juste un listener qui délégue son comportement à quelquechose mais bien une action réutilisable. Vous pourriez aussi étendre vos actions pour les réutiliser ne dehors de Swing, via une application web ou une ligne de commande.

L'idée est vraiment de définir une classe "autonome" pour chaque action, pas juste un listener. Mais, encore une fois, ce qui fonctionne c'est ce qui vous convient.
Developpez.com décline toute responsabilité quant à l'utilisation des différents éléments téléchargés.