LECON 312


Les menus
Tout le monde sait ce qu'est un menu.
Une barre dans laquelle se trouve une ou plusieurs listes déroulantes, elles-mêmes composées de listes.
Vous avez un exemple sous les yeux, tout en haut de votre navigateur internet.

Dans ce chapitre nous allons voir comment ajouter ce genre de composants dans vos fenêtres, mais aussi comment les utiliser.
Nous aborderons aussi la façon d'utiliser ce qu'on appelle des accélérateurs : par exemple, sous Firefox, si vous faites CTRL + T, vous ouvrez un nouvel onglet. Ce raccourci est un exemple d'accélérateur.

Au cours de ce chapitre nous verrons aussi les mnémoniques : dans la barre de menu de votre navigateur, vous pouvez voir qu'une des lettres de chaque élément de menu est soulignée, ceci signifie que si vous appuyez simultanément sur ALT + <la lettre soulignée>, vous déroulerez le menu correspondant. Voici ce qu'on nomme un mnémonique.

Ce type de menu, dit barre de menus, est le plus courant ; mais nous verrons aussi comment utiliser un menu contextuel.
Vous savez, celui qui apparaît lorsque vous faites un clic droit...
Et en bonus, nous apprendrons aussi à utiliser les barres d'outils.

Allez, assez de blabla ! Let's go.
Sommaire du chapitre :
  • La barre de menus et les éléments de menu
  • Faire un menu contextuel
  • Les barres d'outils
  • Utiliser les actions abstraites
  • Ce qu'il faut retenir

La barre de menus et les éléments de menu

Vous vous rappelez que j'ai mentionné une MenuBar faisant partie de la composition de l'objet JFrame.

Le moment est venu pour vous d'utiliser un tel composant : cependant, celui cité ci-dessus appartient au package java.awt. Dans ce chapitre nous utiliserons son homologue, l'objet JMenuBar, présent dans le package javax.swing.

Un menu simple



Afin de travailler avec des menus, nous allons avoir besoin :
  • d'objets JMenu : titre global d'un point de menu. Regardez en haut de votre navigateur ;
  • d'objets JMenuItem : éléments composants nos menus.

Ici, afin de pouvoir utiliser nos futurs menus, nous allons devoir coder des implémentations de l'interface ActionListener : vous la connaissez bien, celle-là !
Ces implémentations serviront à écouter les objets JMenuItem. Ce sont ces objets qui déclencheront tel ou tel traitement. Les JMenu, eux, ont un comportement automatique. Si on clique sur un titre de menu, celui-ci se déroule tout seul et, dans le cas où nous avons un tel objet présent dans un autre JMenu, une autre liste se déroulera toute seule !

En bref, nous n'avons à gérer qu'une partie de tous ces objets.
Bon : nous allons pouvoir commencer. Je vous propose donc d'enlever tous les composants (bouton, combo, checkbox) de notre animation et de gérer tout cela par le biais d'un menu.

Avant de nous lancer dans cette tâche, je vais vous montrer un exemple d'utilisation, histoire de vous familiariser. Voici un code d'exemple :

Code : Java -
 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
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
 
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
 
 
public class ZFenetre extends JFrame {
 
        private JMenuBar menuBar = new JMenuBar();
        private JMenu test1 = new JMenu("Fichier");
        private JMenu test2 = new JMenu("Edition");
               
        private JMenuItem item1 = new JMenuItem("Ouvrir");
        private JMenuItem item2 = new JMenuItem("Fermer");
        private JMenuItem item3 = new JMenuItem("Lancer");
        private JMenuItem item4 = new JMenuItem("Arrêter");
               
               
        public ZFenetre(){
               this.setSize(400, 200);
               this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
               this.setLocationRelativeTo(null);
                       
               //On initialise nos menus
               //--------------------------
                       
               this.test1.add(item1);
               item2.addActionListener(new ActionListener(){
                       public void actionPerformed(ActionEvent arg0) {
                               System.exit(0);
                       }                              
               });
               this.test1.add(item2);
                       
               this.test2.add(item3);
               this.test2.add(item4);
                       
                //L'ordre d'ajout va déterminer l'ordre d'apparition dans le menu de gauche à droite
                //Le premier ajouté sera tout à gauche de la barre de menu et inversement pour le dernier
                       this.menuBar.add(test1);
                       this.menuBar.add(test2);
                       //-------------------------
                       
                       this.setJMenuBar(menuBar);
                       this.setVisible(true);
               }
}

L'action attachée au JMenutItem "Fermer" permet de quitter l'application.
Et le résultat de ce code :



Voici notre exemple un peu plus élaboré :


Code : Java -
 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
82
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
 
import javax.swing.ButtonGroup;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JRadioButtonMenuItem;
 
 
public class ZFenetre extends JFrame {
 
        private JMenuBar menuBar = new JMenuBar();
        private JMenu test1 = new JMenu("Fichier");
        private JMenu test1_2 = new JMenu("Sous ficher");
        private JMenu test2 = new JMenu("Edition");
               
        private JMenuItem item1 = new JMenuItem("Ouvrir");
        private JMenuItem item2 = new JMenuItem("Fermer");
        private JMenuItem item3 = new JMenuItem("Lancer");
        private JMenuItem item4 = new JMenuItem("Arrêter");
        
        private JCheckBoxMenuItem jcmi1 = new JCheckBoxMenuItem("Choix 1");
        private JCheckBoxMenuItem jcmi2 = new JCheckBoxMenuItem("Choix 2");
        
        private JRadioButtonMenuItem jrmi1 = new JRadioButtonMenuItem("Radio 1");
        private JRadioButtonMenuItem jrmi2 = new JRadioButtonMenuItem("Radio 2");
        
        public static void main(String[] args){
               ZFenetre zFen = new ZFenetre();
        }
        
        public ZFenetre(){
               this.setSize(400, 200);
               this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
               this.setLocationRelativeTo(null);
                       
               //On initialise nos menus
               //--------------------------                  
               this.test1.add(item1);
               
               //On ajoute les éléments dans notre sous-menu
               this.test1_2.add(jcmi1);
               this.test1_2.add(jcmi2);
               //Ajout d'un séparateur
               this.test1_2.addSeparator();
               //On met nos radios dans un ButtonGroup
               ButtonGroup bg = new ButtonGroup();
               bg.add(jrmi1);
               bg.add(jrmi2);
                //On présélectionne la première radio
               jrmi1.setSelected(true);
 
               this.test1_2.add(jrmi1);
               this.test1_2.add(jrmi2);
               
               //Ajout du sous-menu dans notre menu
               this.test1.add(this.test1_2);
               //Ajout d'un séparateur
               this.test1.addSeparator();
               item2.addActionListener(new ActionListener(){
                       public void actionPerformed(ActionEvent arg0) {
                               System.exit(0);
                       }                              
               });
               this.test1.add(item2);
                       
               this.test2.add(item3);
               this.test2.add(item4);
                       
                //L'ordre d'ajout va déterminer l'ordre d'apparition dans le menu de gauche à droite
                //Le premier ajouté sera tout à gauche de la barre de menu et inversement pour le dernier
                       this.menuBar.add(test1);
                       this.menuBar.add(test2);
                       //-------------------------
                       
                       this.setJMenuBar(menuBar);
                       this.setVisible(true);
               }
}


Et voilà le rendu de ce code :


Vous pouvez voir qu'il n'y a rien de difficile à créer un menu. Je vous propose donc d'en créer un pour notre animation. Nous allons faire ceci petit à petit. Nous gèrerons les événements ensuite. Pour le moment, nous allons avoir besoin :
  • d'un menu animation, pour lancer, arrêter (par défaut à setEnabled(false)) ou quitter l'animation ;
  • d'un menu forme, afin de savoir quel type de forme utiliser (sous-menu + une radio par forme) et si celle-ci est en mode morphing (case à cocher) ;
  • d'un menu à propos, avec un zoli "?" qui va ouvrir une boîte de dialogue.


N'effacez surtout pas les implémentations pour les événements, retirez seulement les composants utilisant les implémentations et créez votre menu !
Vous serez sans doute obligés de mettre quelques instructions en commentaire... Mais nous y reviendrons.

Je vous laisse faire, vous devriez y arriver sans problème... Prenez votre temps, réfléchissez, et allez-y !

Voici le code que vous devriez avoir (ou un code s'en approchant) :

Code : Java -
  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
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
 
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;
 
public class Fenetre extends JFrame{
 
        private Panneau pan = new Panneau();
    private JPanel container = new JPanel();
    private int compteur = 0;
    private boolean animated = true;
    private boolean backX, backY;
    private int x,y ;
    private Thread t;
    
    private JMenuBar menuBar = new JMenuBar();
    
    private JMenu animation = new JMenu("Animation"),
               forme = new JMenu("Forme"),
               typeForme = new JMenu("Type de forme"),
               aPropos = new JMenu("À propos");
    
    private JMenuItem lancer = new JMenuItem("Lancer l'animation"),
                               arreter = new JMenuItem("Arrêter l'animation"),
                               quitter = new JMenuItem("Quitter"),
                               aProposItem = new JMenuItem("?");
    
    private JCheckBoxMenuItem morph = new JCheckBoxMenuItem("Morphing");
    private JRadioButtonMenuItem carre = new JRadioButtonMenuItem("Carré"),
                                                     rond = new JRadioButtonMenuItem("Rond"),
                                                     triangle = new JRadioButtonMenuItem("Triangle"),
                                                     etoile = new JRadioButtonMenuItem("Etoile");
                                                     
    private ButtonGroup bg = new ButtonGroup();
    
    public Fenetre(){
           
            this.setTitle("Animation");
            this.setSize(300, 300);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.setLocationRelativeTo(null);
 
            container.setBackground(Color.white);
            container.setLayout(new BorderLayout());
            container.add(pan, BorderLayout.CENTER);
            
            this.setContentPane(container);
            this.initMenu();
            this.setVisible(true);            
                        
    }
        
    private void initMenu(){
        //Menu animation
        animation.add(lancer);
        arreter.setEnabled(false);
        animation.add(arreter);
        animation.addSeparator();
        //Pour quitter l'application
        quitter.addActionListener(new ActionListener(){
               public void actionPerformed(ActionEvent event){
                       System.exit(0);
               }
        });
        animation.add(quitter);
        
        //Menu forme
        
        bg.add(carre);
        bg.add(triangle);
        bg.add(rond);
        bg.add(etoile);
        
        typeForme.add(rond);
        typeForme.add(carre);          
        typeForme.add(triangle);
        typeForme.add(etoile);
        
        rond.setSelected(true);
 
        forme.add(typeForme);
        forme.add(morph);
        
        //menu à propos
        aPropos.add(aProposItem);
        
        //Ajout des menus dans la barre de menus
        menuBar.add(animation);
        menuBar.add(forme);
        menuBar.add(aPropos);
        
        //Ajout de la barre de menus sur la fenêtre
        this.setJMenuBar(menuBar);
    }
    
        private void go(){
               x = pan.getPosX();
               y = pan.getPosY();
        while(this.animated){
               //System.out.println("OK");
               //Si le mode morphing est activé, on utilise la taille actuelle de la forme
               if(pan.isMorph())
               {
                       if(x < 1)backX = false;
                    if(x > pan.getWidth() - pan.getDrawSize())backX = true;               
                    if(y < 1)backY = false;
                    if(y > pan.getHeight() - pan.getDrawSize())backY = true;
               }
               //Sinon, comme d'habitude
               else
               {
                       if(x < 1)backX = false;
                    if(x > pan.getWidth()-50)backX = true;               
                    if(y < 1)backY = false;
                    if(y > pan.getHeight()-50)backY = true;
               }  
            
               if(!backX)pan.setPosX(++x);
            else pan.setPosX(--x);
            if(!backY) pan.setPosY(++y);
            else pan.setPosY(--y);
            pan.repaint();
 
            try {
                    Thread.sleep(3);
            } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
            }
        }       
        }
 
        public class BoutonListener implements ActionListener{
 
               public void actionPerformed(ActionEvent arg0) {
                       
                       JOptionPane jop = new JOptionPane();                  
                       int option = jop.showConfirmDialog(null, "Voulez-vous lancer l'animation ?", "Lancement de l'animation", JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE);
                       
                       if(option == JOptionPane.OK_OPTION)
                       {
                               lancer.setEnabled(false);
                               arreter.setEnabled(true);
                               animated = true;
                               t = new Thread(new PlayAnimation());
                               t.start();                     
                       }
               }              
        }
        
        class Bouton2Listener  implements ActionListener{
 
               public void actionPerformed(ActionEvent e) {
                       
                       JOptionPane jop = new JOptionPane();                  
                       int option = jop.showConfirmDialog(null, "Voulez-vous arrêter l'animation ?", "Arrêt de l'animation", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
                       
                       if(option != JOptionPane.NO_OPTION && option != JOptionPane.CANCEL_OPTION && option != JOptionPane.CLOSED_OPTION)
                       {
                               animated = false;
                               //On remplace nos boutons par nos JMenuItem
                               lancer.setEnabled(true);
                               arreter.setEnabled(false);
                       }
               }              
        }       
        
        class PlayAnimation implements Runnable{
 
               public void run() {
                       go();                  
               }              
        }
        
        
        class FormeListener implements ActionListener{
 
               public void actionPerformed(ActionEvent e) {
                       
                       //On commente cette ligne pour l'instant
                       //****************************************
                       //pan.setForme(combo.getSelectedItem().toString());
               }              
        }
        
        class MorphListener implements ActionListener{
 
               public void actionPerformed(ActionEvent e) {
                       //Si la case est cochée, activation du mode morphing
                       if(morph.isSelected())pan.setMorph(true);
                       //Sinon rien !
                       else pan.setMorph(false);
               }              
        }       
}


Ce que vous devez obtenir :


Vous pouvez remarquer que notre IHM est beaucoup plus propre...

Il ne nous reste plus qu'à faire interagir nos menus avec notre animation ! Rien de plus simple, il suffit de dire à nos MenuItem qu'une implémentation les écoutent. En fait, cela revient à faire comme si nous cliquions sur des boutons, à l'exception des cases à cocher et des radios où, là, nous pouvons utiliser une implémentation d'ActionListener ou d'ItemListener : nous utiliserons la première.

Afin que l'application fonctionne bien, j'ai apporté deux modifications mineures dans la classe Panneau :
  • ajout d'une instruction dans une condition, celle-ci :
    Code : Java -
1
2
3
4
//J'ai rajouté :  || this.forme.equals("CARRÉ")
if(this.forme.equals("CARRE") || this.forme.equals("CARRÉ")){
        g.fillRect(posX, posY, 50, 50);
}

  • Pour accepter les deux orthographe !
  • ajout d'un toUpperCase() dans :
    Code : Java -
1
2
3
public void setForme(String form){            
     this.forme = form.toUpperCase();
}

  • Afin d'être sûr que le test sur cette chaîne de caractères soit sur des majuscules...


Voici le code de notre animation avec un beau menu pour tout contrôler :

Code : Java -
  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
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
 
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;
 
public class Fenetre extends JFrame{
 
        private Panneau pan = new Panneau();
    private JPanel container = new JPanel();
    private int compteur = 0;
    private boolean animated = true;
    private boolean backX, backY;
    private int x,y ;
    private Thread t;
    
    private JMenuBar menuBar = new JMenuBar();
    
    private JMenu animation = new JMenu("Animation"),
               forme = new JMenu("Forme"),
               typeForme = new JMenu("Type de forme"),
               aPropos = new JMenu("À propos");
    
    private JMenuItem lancer = new JMenuItem("Lancer l'animation"),
                               arreter = new JMenuItem("Arrêter l'animation"),
                               quitter = new JMenuItem("Quitter"),
                               aProposItem = new JMenuItem("?");
    
    private JCheckBoxMenuItem morph = new JCheckBoxMenuItem("Morphing");
    private JRadioButtonMenuItem carre = new JRadioButtonMenuItem("Carré"),
                                                     rond = new JRadioButtonMenuItem("Rond"),
                                                     triangle = new JRadioButtonMenuItem("Triangle"),
                                                     etoile = new JRadioButtonMenuItem("Etoile");
                                                     
    private ButtonGroup bg = new ButtonGroup();
    
    public Fenetre(){
           
            this.setTitle("Animation");
            this.setSize(300, 300);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.setLocationRelativeTo(null);
 
            container.setBackground(Color.white);
            container.setLayout(new BorderLayout());
            container.add(pan, BorderLayout.CENTER);
            
            this.setContentPane(container);
            this.initMenu();
            this.setVisible(true);            
                        
    }
        
    private void initMenu(){
        //Menu animation
        //****************************
        
        //Ajout du listener pour lancer l'animation
        lancer.addActionListener(new StartAnimationListener());
        animation.add(lancer);
        
        //Ajout du listener pour arrêter l'animation
        arreter.addActionListener(new StopAnimationListener());
        arreter.setEnabled(false);
        animation.add(arreter);
        
        animation.addSeparator();
        quitter.addActionListener(new ActionListener(){
               public void actionPerformed(ActionEvent event){
                       System.exit(0);
               }
        });
        animation.add(quitter);
        
        //Menu forme
        
        bg.add(carre);
        bg.add(triangle);
        bg.add(rond);
        bg.add(etoile);
        
        //On crée un nouvel écouteur, inutile de créer 4 instances différentes
        FormeListener fl = new FormeListener();
        carre.addActionListener(fl);
        rond.addActionListener(fl);
        triangle.addActionListener(fl);
        etoile.addActionListener(fl);
        
        typeForme.add(rond);
        typeForme.add(carre);          
        typeForme.add(triangle);
        typeForme.add(etoile);
        
        rond.setSelected(true);
        
        forme.add(typeForme);
        
        //Ajout du listener pour le morphing
        morph.addActionListener(new MorphListener());
        forme.add(morph);
        
        //menu à propos
        
        //Ajout de ce que doit faire le "?"
        aProposItem.addActionListener(new ActionListener(){
                       public void actionPerformed(ActionEvent arg0) {
                               JOptionPane jop = new JOptionPane();
                               ImageIcon img = new ImageIcon("images/cysboy.gif");
                               
                               String mess = "Merci ! \n J'espère que vous vous amusez bien ! \n";
                               mess += "Je crois qu'il est temps d'ajouter des accélérateurs et des mnémoniques dans tout ça...\n";
                               mess += "\n Allez, GO les ZérOs !";
                               
                               jop.showMessageDialog(null, mess, "À propos", JOptionPane.INFORMATION_MESSAGE, img);
                               
                       }                             
        });
        aPropos.add(aProposItem);
        
        //Ajout des menus dans la barre de menus
        menuBar.add(animation);
        menuBar.add(forme);
        menuBar.add(aPropos);
        
        //Ajouit de la barre de menus sur la fenêtre
        this.setJMenuBar(menuBar);
    }
    
        private void go(){
               x = pan.getPosX();
               y = pan.getPosY();
        while(this.animated){
               //System.out.println("OK");
               //Si le mode morphing est activé, on utilise la taille actuelle de la forme
               if(pan.isMorph())
               {
                       if(x < 1)backX = false;
                    if(x > pan.getWidth() - pan.getDrawSize())backX = true;               
                    if(y < 1)backY = false;
                    if(y > pan.getHeight() - pan.getDrawSize())backY = true;
               }
               //Sinon, comme d'habitude
               else
               {
                       if(x < 1)backX = false;
                    if(x > pan.getWidth()-50)backX = true;               
                    if(y < 1)backY = false;
                    if(y > pan.getHeight()-50)backY = true;
               }  
            
               if(!backX)pan.setPosX(++x);
            else pan.setPosX(--x);
            if(!backY) pan.setPosY(++y);
            else pan.setPosY(--y);
            pan.repaint();
 
            try {
                    Thread.sleep(3);
            } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
            }
        }       
        }
        
        /**
         * Ecouteur du menu Lancer
         * @author CHerby
         */
        public class StartAnimationListener implements ActionListener{
 
               public void actionPerformed(ActionEvent arg0) {
                       
                       JOptionPane jop = new JOptionPane();                  
                       int option = jop.showConfirmDialog(null, "Voulez-vous lancer l'animation ?", "Lancement de l'animation", JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE);
                       
                       if(option == JOptionPane.OK_OPTION)
                       {
                               lancer.setEnabled(false);
                               arreter.setEnabled(true);
                               animated = true;
                               t = new Thread(new PlayAnimation());
                               t.start();                     
                       }
               }              
        }
        
        /**
         * Ecouteur du menu Quitter
         * @author CHerby
         */
        class StopAnimationListener  implements ActionListener{
 
               public void actionPerformed(ActionEvent e) {
                       
                       JOptionPane jop = new JOptionPane();                  
                       int option = jop.showConfirmDialog(null, "Voulez-vous arrêter l'animation ?", "Arrêt de l'animation", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
                       
                       if(option != JOptionPane.NO_OPTION && option != JOptionPane.CANCEL_OPTION && option != JOptionPane.CLOSED_OPTION)
                       {
                               animated = false;
                               //On remplace nos boutons par nos JMenuItem
                               lancer.setEnabled(true);
                               arreter.setEnabled(false);
                       }
               }              
        }       
        
        /**
         * Lance le thread.
         * @author CHerby
         */
        class PlayAnimation implements Runnable{
               public void run() {
                       go();                  
               }              
        }       
        
        /**
         * Ecoute les menus forme
         * @author CHerby
         */
        class FormeListener implements ActionListener{
               public void actionPerformed(ActionEvent e) {
                       pan.setForme(((JRadioButtonMenuItem)e.getSource()).getText());
               }              
        }
        
        /**
         * Ecoute le menu Morphing
         * @author CHerby
         */
        class MorphListener implements ActionListener{
               public void actionPerformed(ActionEvent e) {
                       //Si la case est cochée, activation du mode morphing
                       if(morph.isSelected())pan.setMorph(true);
                       //Sinon rien !
                       else pan.setMorph(false);
               }              
        }       
}

J'ai modifié le nom des implémentations et j'ai ajouté mon avatar du SDZ dans le dialogue du menu "À propos". Mettez une image si vous avez envie...


Comme je l'ai dit dans le dialogue du menu "À propos", je crois qu'il est temps de mettre des raccourcis clavier dans tout ceci !
Vous êtes prêts ?

Les raccourcis clavier



En fait, ceci est très simple aussi. Pour ajouter un accélérateur sur un JMenu, nous appelerons la méthode setAccelerator(); et pour ajouter un mnémonique sur un JMenuItem, nous invoquerons la méthode setMnemonic();.

Attribuons le mnémonique 'A' pour le menu "Animation", le mnémonique 'F' pour le menu "Forme" et enfin 'P' pour "À propos". Vous allez voir, c'est très simple : il vous suffit d'invoquer la méthode setMnemonic(char mnemonic); sur le JMenu que vous désirez.

Ce qui nous donne, dans notre cas :

Code : Java -
 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
private void initMenu(){
        //Menu animation
        //****************************
 
        //Ajout du listener pour lancer l'animation
        lancer.addActionListener(new StartAnimationListener());
        animation.add(lancer);
        
        //Ajout du listener pour arrêter l'animation
        arreter.addActionListener(new StopAnimationListener());
        arreter.setEnabled(false);
        animation.add(arreter);
        
        animation.addSeparator();
        quitter.addActionListener(new ActionListener(){
               public void actionPerformed(ActionEvent event){
                       System.exit(0);
               }
        });
        animation.add(quitter);
        
        //Menu forme
        
        bg.add(carre);
        bg.add(triangle);
        bg.add(rond);
        bg.add(etoile);
        
        //On crée un nouvel écouteur, inutile de créer 4 instances différentes
        FormeListener fl = new FormeListener();
        carre.addActionListener(fl);
        rond.addActionListener(fl);
        triangle.addActionListener(fl);
        etoile.addActionListener(fl);
        
        typeForme.add(rond);
        typeForme.add(carre);          
        typeForme.add(triangle);
        typeForme.add(etoile);
        
        rond.setSelected(true);
        
        forme.add(typeForme);
        
        //Ajout du listener pour le morphing
        morph.addActionListener(new MorphListener());
        forme.add(morph);
        
        //menu à propos
        
        //Ajout de ce que doit faire le "?"
        aProposItem.addActionListener(new ActionListener(){
                       public void actionPerformed(ActionEvent arg0) {
                               JOptionPane jop = new JOptionPane();
                               ImageIcon img = new ImageIcon("images/cysboy.gif");
                               
                               String mess = "Merci ! \n J'espère que vous vous amusez bien ! \n";
                               mess += "Je crois qu'il est temps d'ajouter des accélérateurs et des mnémoniques dans tout ça...\n";
                               mess += "\n Allez, GO les ZérOs !";
                               
                               jop.showMessageDialog(null, mess, "À propos", JOptionPane.INFORMATION_MESSAGE, img);
                               
                       }                             
        });
        aPropos.add(aProposItem);
        
        //Ajout des menus dans la barre de menus ET AJOUT DE MNEMONICS ! !
        animation.setMnemonic('A');
               menuBar.add(animation);
        
               forme.setMnemonic('F');
               menuBar.add(forme);
                       
               aPropos.setMnemonic('P');
               menuBar.add(aPropos);          
        //Ajouit de la barre de menus sur la fenêtre
        this.setJMenuBar(menuBar);
    }


Nous avons à présent les lettres correspondantes soulignées dans nos menus, et mieux encore, si vous tapez ALT + <la lettre> : le menu correspondant se déroule !

Voici ce que j'obtiens :

Concernant les mnémoniques, vous devez savoir que vous pouvez aussi en mettre sur les objets JMenuItem.
Il faut que vous sachiez aussi qu'il existe une autre façon d'ajouter un mnémonique sur un JMenu mais UNIQUEMENT SUR UN JMenu : en passant le mnémonique en deuxième paramètre du constructeur de l'objet, comme ceci JMenu menu = new JMenu("Fichier", 'F');//Ici, ce menu aura le mnémonique F.


Oui, je sais, c'est simple et même très simple. Pour ajouter des accélérateurs, c'est quasiment pareil sauf que nous devrons utiliser un nouvel objet : KeyStroke.
Cet objet permet de connaître l'identité de la touche utilisée ou à utiliser. De ce fait, c'est grâce à cet objet que nous allons pouvoir construire des combinaisons de touches pour nos accélérateurs !

Nous allons commencer par attribuer un simple caractère comme accélérateur pour notre JMenuItem "Lancer", ceci en utilisant la méthode getKeyStroke(char caracter); de l'objet KeyStroke.

Rajoutez cette ligne de code au début de la méthode initMenu() :

Code : Java -
1
2
//Cette instruction ajoute l'accélérateur 'c' à notre objet
lancer.setAccelerator(KeyStroke.getKeyStroke('c'));

Vous aurez besoin de ces packages : javax.swing.KeyStroke et java.awt.event.ActionEvent


Testez votre application et vous devriez vous rendre compte qu'un petit 'c' est apparu à côté du menu "Lancer".

Voyez plutôt :


Et, si vous appuyez sur la touche 'c' de votre clavier, celle-ci a le même effet qu'un clic sur le menu "Lancer" !
Attention : si vous mettez le caractère 'C', vous serez obligés d'appuyer simultanément sur SHIFT + c ou alors d'avoir la touche MAJ activée !


Le principe est bien, cependant, imaginez aussi que, maintenant, votre touche 'c' vous demandera systématiquement le lancement de votre animation !
C'est l'une des raisons pour laquelle les accélérateurs sont, en général, des combinaisons de touches du genre CTRL + c ou encore CTRL + SHIFT + S.

Pour réussir à faire ceci, nous allons utiliser une autre méthode getKeyStroke() : celle-ci prendra non pas le caractère de notre touche, mais son code, ainsi qu'une ou plusieurs touches faisant la combinaison !
Pour obtenir le code d'une touche, nous utiliserons l'objet KeyEvent, qui stocke tous les codes de touches !


Dans le code qui suit, je crée un accélérateur CTRL + L pour le menu "Lancer" et un accélérateur CTRL + SHIT + A pour le menu "Arrêter" :

Code : Java -
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
lancer.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L,
                                              KeyEvent.CTRL_MASK));
        animation.add(lancer);
        
        //Ajout du listener pour arrêter l'animation
        arreter.addActionListener(new StopAnimationListener());
        arreter.setEnabled(false);
        arreter.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A,
                                                    KeyEvent.CTRL_DOWN_MASK + KeyEvent.SHIFT_DOWN_MASK));
        animation.add(arreter);


Et ceci nous donne :

 
À ce moment-ci, j'imagine que vous devez être perturbés par ceci : KeyEvent.VK_L et les appels du même genre.

En fait, la classe KeyEvent répertorie tous les codes de toutes les touches du clavier. Une grande majorité sont sous la forme VK_<le caractère ou le nom de la touche>, lisez ceci comme : Value of Key <nom de la touche>.
Mis à part certaines touches de contrôle comme CTRL, ALT, SHIFT... vous pouvez retrouver facilement le code d'une touche grâce à cet objet !

Ensuite, vous avez dû remarquer que lorsque vous avez voulu taper KeyEvent.CTRL_DOWN_MASK, Eclipse vous propose quasiment la même chose :


Vous pouvez aisément voir qu'Eclipse vous dit que la version CTRL_DOWN_MASK est la plus récente et qu'il est vivement conseillé de l'utiliser !
Maintenant que vous savez comment créer des mnémoniques et des accélérateurs, mettez-en où vous voulez ! Ceci dépend de vous...


Vous voilà donc avec un zoli menu avec des mnémoniques et des accélérateurs.
Il est donc temps de voir comment créer un menu contextuel !

Faire un menu contextuel

Vous allez vous rendre compte que vous avez déjà fait le plus dur...
Nous allons seulement utiliser un autre objet : un JPopupMenu. Dans lequel nous allons mettre nos JMenuItem ou / et JMenu.

Il va falloir tout de même dire à notre menu contextuel comment s'afficher et surtout où, mais vous verrez que c'est très simple...

Maintenant que vous commencez à bien connaître les principes de bases de la programmation événementielle, nous allons aller plus vite pour apprendre de nouvelles choses !

Les points importants pour notre menu contextuel


  • Les actions à effectuer, dans le cas d'actions identiques au menu, doivent être les mêmes : nous devrons donc créer des objets globaux aux deux menus.
  • Le menu contextuel ne doit s'afficher que dans la zone où l'animation s'exécute, et non sur le menu !
  • Il ne doit s'afficher que lorsqu'on fait un clic droit, et uniquement ça !


Nous allons mettre, dans notre menu contextuel, les actions "Lancer l'animation" et "Arrêter l'animation" ainsi que deux nouveautés :
  • pouvoir changer la couleur du fond de notre animation ;
  • avoir la possibilité de changer la couleur de notre forme !


Avant d'implémenter les deux nouvelles fonctionnalités, nous allons travailler sur les deux premières.
Ce qui signifie que, lorsque nous lancerons l'animation, nous devrons mettre les deux menus "Lancer l'animation" à l'état setEnabled(false); et les deux menus "Arrêter l'animation" à l'état setEnabled(true);, et inversement pour l'arrêt.

Comme je vous l'ai dit plus haut, nous allons utiliser le même objet écouteur pour le traitement des deux menus, nous allons devoir créer une véritable instance de ces objets et avertir que ces objets écoutent non seulement le menu du haut, mais aussi le menu contextuel.
Nous avons parfaitement le droit de faire ça : plusieurs écouteurs peuvent écouter un composant et plusieurs composants peuvent avoir le même écouteur !

Vous êtes presque prêts à créer votre menu contextuel, il ne vous manque que trois informations :
  • comment dire à notre panneau d'afficher le menu contextuel ? Et où ?
  • comment lui spécifier qu'il doit le faire uniquement sur le clic droit ?


Le déclenchement de l'affichage de la popup doit se faire sur un clic de souris, vous connaissez une interface qui gère ce type d'événement : l'interface MouseListener. Nous allons donc dire à notre panneau qu'un écouteur du type de cet interface va l'écouter !
Tout comme lors du chapitre sur les zones de saisie, il existe une classe qui contient toutes les méthodes de la dite interface : la classe MouseAdapter.
Vos pouvez utiliser celle-ci pour créer une implémentation afin de ne redéfinir que la méthode dont vous avez besoin ! C'est cette solution que nous allons utiliser.

Quelle méthode doit-on redéfinir ? mouseClicked() ?

Si vous voulez, mais je pensais plutôt à mouseReleased(), pour une raison simple que vous ne devez sûrement pas connaître : ces deux événements sont quasiment identiques, cependant, dans un certain cas, seul l'événement mouseClicked() sera appelé. Il s'agit du cas où vous cliquez sur une zone, que vous déplacez votre souris tout en maintenant le clic et que vous relâchez le bouton de la souris ensuite.

C'est pour cette raison que je préfère utiliser la méthode mouseReleased(). Ensuite, pour spécifier où afficher le menu contextuel, la classe JPopupMenu possède une méthode show(Component invoker, int x, int y);.
  • Component invoker : désigne l'objet invoquant le menu contextuel, dans notre cas, notre instance de Panneau.
  • int x: coordonnée X du menu.
  • int y: Coordonnée Y du menu.

Souvenez-vous que vous pouvez déterminer les coordonnées de la souris grâce à l'objet passé en paramètre de la méthode mouseReleased(MouseEvent event).


Je suis sûr que vous savez comment vous y prendre pour dire au menu contextuel de s'afficher, il ne vous manque plus qu'à détecter le clic droit. Et là, l'objet MouseEvent va vous sauver la mise !
En effet, cet objet possède une méthode isPopupTrigger() qui renvoie vrai s'il s'agit d'un clic droit.

Vous avez tous les éléments en mains pour faire votre menu contextuel, rappelez-vous que nous ne gérons pas tout de suite les nouvelles fonctionnalités...

Quelques instants de réflexion... Vous avez fini ? Nous pouvons comparer nos codes ?
                import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.KeyStroke;

public class Fenetre extends JFrame{

                private Panneau pan = new Panneau();
    private JPanel container = new JPanel();
    private int compteur = 0;
    private boolean animated = true;
    private boolean backX, backY;
    private int x,y ;
    private Thread t;
   
   

    //***********************************************************
    //                                       La déclaration pour le menu de la JMenuBar
    //***********************************************************
    private JMenuBar menuBar = new JMenuBar();
   
    private JMenu animation = new JMenu("Animation"),
                               forme = new JMenu("Forme"),
                               typeForme = new JMenu("Type de forme"),
                               aPropos = new JMenu("À propos");
   
    private JMenuItem    lancer = new JMenuItem("Lancer l'animation"),
                                                                               arreter = new JMenuItem("Arrêter l'animation"),
                                                                               quitter = new JMenuItem("Quitter"),
                                                                               aProposItem = new JMenuItem("?");
                   
    private JCheckBoxMenuItem morph = new JCheckBoxMenuItem("Morphing");
    private JRadioButtonMenuItem          carre = new JRadioButtonMenuItem("Carré"),
                                                                                                                              rond = new JRadioButtonMenuItem("Rond"),
                                                                                                                              triangle = new JRadioButtonMenuItem("Triangle"),
                                                                                                                              etoile = new JRadioButtonMenuItem("Etoile");
                                                                                                                             
    private ButtonGroup bg = new ButtonGroup();
   
    //***********************************************************
    //                                       La déclaration pour le menu contextuel
    //***********************************************************
    private JPopupMenu jpm = new JPopupMenu();
    private JMenu background = new JMenu("Couleur de fond");
    private JMenu couleur = new JMenu("Couleur de la forme");
               
    private JMenuItem launch = new JMenuItem("Lancer l'animation");                                              
    private JMenuItem stop = new JMenuItem("Arrêter l'animation");
    private JMenuItem    rouge = new JMenuItem("Rouge"),
                                                                                  bleu = new JMenuItem("Bleu"),
                                                                                  vert = new JMenuItem("Vert"),
                                                                                  rougeBack = new JMenuItem("Rouge"),
                                                                                  bleuBack = new JMenuItem("Bleu"),
                                                                                  vertBack = new JMenuItem("Vert");

    //***********************************************************
    //                                                       ON CRÉE DES LISTENER GLOBAUX
    //***********************************************************
    private StopAnimationListener stopAnimation = new StopAnimationListener();
    private StartAnimationListener startAnimation = new StartAnimationListener();
   
   
    //**********************************************************
   
    public Fenetre(){
          
            this.setTitle("Animation");
            this.setSize(300, 300);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.setLocationRelativeTo(null);

            container.setBackground(Color.white);
            container.setLayout(new BorderLayout());
           
            //On initialise le menu stop
            stop.setEnabled(false);
            //On affecte les écouteurs
            stop.addActionListener(stopAnimation);
                               launch.addActionListener(startAnimation);
           
                               //On crée et on passe l'écouteur pour afficher le menu contextuel
                               //Création d'une implémentation de MouseAdapter
                               //avec redéfinition de la méthode adéquate
            pan.addMouseListener(new MouseAdapter(){
                public void mouseReleased(MouseEvent event){
                               //Seulement s'il s'agit d'un clic droit
                               //Vous pouvez aussi utiliser cette méthode pour détecter le clic droit
                        //if(event.getButton() == MouseEvent.BUTTON3)
                        if(event.isPopupTrigger())
                               {                                            
                                               background.add(rougeBack);
                                               background.add(bleuBack);
                                               background.add(vertBack);
                                              
                                               couleur.add(rouge);
                                               couleur.add(bleu);
                                               couleur.add(vert);
                                              
                                               jpm.add(launch);
                                               jpm.add(stop);
                                               jpm.add(couleur);
                                               jpm.add(background);
                                              
                                               //La méthode qui va afficher le menu
                                               jpm.show(pan, event.getX(), event.getY());
                               }
                }
            });
           
            container.add(pan, BorderLayout.CENTER);
           
            this.setContentPane(container);
            this.initMenu();
            this.setVisible(true);           
                       
    }
               
    private void initMenu(){
                //Menu animation
                //****************************
               
                //Ajout du listener pour lancer l'animation
                //ATTENTION LE LISTENER EST GLOBAL ! ! ! !
                //-----------------------------------------------
                lancer.addActionListener(startAnimation);
                //On attribut l'accélerateur c
                lancer.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L,
                                                                                                                                                                                            KeyEvent.CTRL_MASK));
                animation.add(lancer);
               
                //Ajout du listener pour arrêter l'animation
                //LISTENER A CHANGER ICI AUSSI
                //--------------------------------------------
                arreter.addActionListener(stopAnimation);
                arreter.setEnabled(false);
                arreter.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A,
                                                                                                                                                                                            KeyEvent.CTRL_DOWN_MASK + KeyEvent.SHIFT_DOWN_MASK));
                animation.add(arreter);
               
                animation.addSeparator();
                quitter.addActionListener(new ActionListener(){
                               public void actionPerformed(ActionEvent event){
                                               System.exit(0);
                               }
                });
                animation.add(quitter);
               
                //Menu forme
               
                bg.add(carre);
                bg.add(triangle);
                bg.add(rond);
                bg.add(etoile);
               
                //On crée un nouvel écouteur, inutile de créer 4 instances différentes
                FormeListener fl = new FormeListener();
                carre.addActionListener(fl);
                rond.addActionListener(fl);
                triangle.addActionListener(fl);
                etoile.addActionListener(fl);
               
                typeForme.add(rond);
                typeForme.add(carre);               
                typeForme.add(triangle);
                typeForme.add(etoile);
               
                rond.setSelected(true);
               
                forme.add(typeForme);
               
                //Ajout du listener pour le morphing
                morph.addActionListener(new MorphListener());
                forme.add(morph);
               
                //menu à propos
               
                //Ajout de ce que doit faire le "?"
                aProposItem.addActionListener(new ActionListener(){
                                               public void actionPerformed(ActionEvent arg0) {
                                                               JOptionPane jop = new JOptionPane();
                                                               ImageIcon img = new ImageIcon("images/cysboy.gif");
                                                              
                                                               String mess = "Merci ! \n J'espère que vous vous amusez bien ! \n";
                                                               mess += "Je crois qu'il est temps d'ajouter des accélérateurs et des mnémoniques dans tout ça...\n";
                                                               mess += "\n Allez, GO les ZérOs !";
                                                              
                                                               jop.showMessageDialog(null, mess, "À propos", JOptionPane.INFORMATION_MESSAGE, img);
                                                              
                                               }                                                            
                });
                aPropos.add(aProposItem);
               
                //Ajout des menus dans la barre de menus
                animation.setMnemonic('A');
                menuBar.add(animation);
               
                forme.setMnemonic('F');
                menuBar.add(forme);
               
                aPropos.setMnemonic('P');
                menuBar.add(aPropos);
               
                //Ajouit de la barre de menus sur la fenêtre
                this.setJMenuBar(menuBar);
    }
   
                private void go(){
                               x = pan.getPosX();
                               y = pan.getPosY();
        while(this.animated){
                //System.out.println("OK");
                //Si le mode morphing est activé, on utilise la taille actuelle de la forme
                               if(pan.isMorph())
                               {
                                               if(x < 1)backX = false;
                            if(x > pan.getWidth() - pan.getDrawSize())backX = true;              
                            if(y < 1)backY = false;
                            if(y > pan.getHeight() - pan.getDrawSize())backY = true;
                               }
                               //Sinon, comme d'habitude
                               else
                               {
                                if(x < 1)backX = false;
                            if(x > pan.getWidth()-50)backX = true;              
                            if(y < 1)backY = false;
                            if(y > pan.getHeight()-50)backY = true;
                               } 
           
                if(!backX)pan.setPosX(++x);
            else pan.setPosX(--x);
            if(!backY) pan.setPosY(++y);
            else pan.setPosY(--y);
            pan.repaint();

            try {
                    Thread.sleep(3);
            } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
            }
        }      
                }
               
                /**
                 * Écouteur du menu Lancer
                 * @author CHerby
                 */
                public class StartAnimationListener implements ActionListener{

                               public void actionPerformed(ActionEvent arg0) {
                                              
                                               JOptionPane jop = new JOptionPane();                                             
                                               int option = jop.showConfirmDialog(null, "Voulez-vous lancer l'animation ?", "Lancement de l'animation", JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE);
                                              
                                               if(option == JOptionPane.OK_OPTION)
                                               {
                                                              lancer.setEnabled(false);
                                                               arreter.setEnabled(true);
                                                              
                                                               //ON AJOUTE L'INSTRUCTION POUR LE MENU CONTEXTUEL
                                                               //************************************************
                                                               launch.setEnabled(false);
                                                               stop.setEnabled(true);
                                                              
                                                               animated = true;
                                                               t = new Thread(new PlayAnimation());
                                                               t.start();                                             
                                               }
                               }                             
                }
               
                /**
                 * Écouteur du menu Quitter
                 * @author CHerby
                 */
                class StopAnimationListener  implements ActionListener{

                               public void actionPerformed(ActionEvent e) {
                                              
                                               JOptionPane jop = new JOptionPane();                                             
                                               int option = jop.showConfirmDialog(null, "Voulez-vous arrêter l'animation ?", "Arrêt de l'animation", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
                                              
                                               if(option != JOptionPane.NO_OPTION && option != JOptionPane.CANCEL_OPTION && option != JOptionPane.CLOSED_OPTION)
                                               {
                                                               animated = false;
                                                               //On remplace nos boutons par nos JMenuItem
                                                               lancer.setEnabled(true);
                                                               arreter.setEnabled(false);

                                                               //ON AJOUTE L'INSTRUCTION POUR LE MENU CONTEXTUEL
                                                               //************************************************
                                                               launch.setEnabled(true);
                                                               stop.setEnabled(false);
                                               }
                               }                             
                }             
               
                /**
                 * Lance le thread.
                 * @author CHerby
                 */
                class PlayAnimation implements Runnable{
                               public void run() {
                                               go();                                    
                               }                             
                }             
               
                /**
                 * Écoute les menus forme
                 * @author CHerby
                 */
                class FormeListener implements ActionListener{
                               public void actionPerformed(ActionEvent e) {
                                               pan.setForme(((JRadioButtonMenuItem)e.getSource()).getText());
                               }                             
                }
               
                /**
                 * Écoute le menu Morphing
                 * @author CHerby
                 */
                class MorphListener implements ActionListener{
                               public void actionPerformed(ActionEvent e) {
                                               //Si la case est cochée, activation du mode morphing
                                               if(morph.isSelected())pan.setMorph(true);
                                               //Sinon rien !
                                               else pan.setMorph(false);
                               }                             
                }             
}


Voici ce que j'obtiens :


Victoire !
Il est beau, il est fonctionnel, il est zérotissime notre menu contextuel !

Je sens que vous êtes prêts pour les nouvelles fonctionnalités... Même si je me doute que certains d'entre vous ont déjà fait ce qu'il fallait.

Il n'est pas très difficile de faire ce genre de chose, surtout que vous êtes habitués, maintenant.
Dans notre classe Panneau, nous utilisons des couleurs définies à l'avance, il nous suffit donc de mettre ces couleurs dans des variables et de permettre l'édition de celles-ci.

Rien de difficile ici, voici donc les codes sources de nos deux classes :

Panneau.java


Code : Java -
  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
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.io.File;
import java.io.IOException;
 
import javax.imageio.ImageIO;
import javax.swing.JPanel;
 
public class Panneau extends JPanel {
 
        private int posX = -50;
    private int posY = -50;
    private int drawSize = 50;
    //boolean pour le mode morphing et pour savoir si la taille doit être réduite
    private boolean morph = false, reduce = false;;
    private String forme = "ROND";
    
    //***********************************
    //Voici nos deux couleurs
    //***********************************
    private Color couleurForme = Color.red;
    private Color couleurFond = Color.white;
    
    //Le compteur de rafraîchissement
    private int increment = 0;
    
    public void paintComponent(Graphics g){
        //affectation de la couleur de fond    
        g.setColor(couleurFond);
            g.fillRect(0, 0, this.getWidth(), this.getHeight());
            
            //Affectation de la couleur de la forme
            g.setColor(couleurForme);
            //Si le mode morphing est activé, on peint le morphing
            if(this.morph)
               drawMorph(g);
            //sinon, mode normal
            else
               draw(g);
    }
 
    
 
    /**
     * Méthode qui redéfinit la couleur du fond
     * @param color
     */
    public void setCouleurFond(Color color){
        this.couleurFond = color;
    }
    
    /**
     * Méthode qui redéfinit la couleur de la forme
     * @param color
     */
    public void setCouleurForme(Color color){
        this.couleurForme = color;
    }
    
    
    private void draw(Graphics g){
        
        if(this.forme.equals("ROND")){
                g.fillOval(posX, posY, 50, 50); 
        }
        if(this.forme.equals("CARRE") || this.forme.equals("CARRÉ")){
               g.fillRect(posX, posY, 50, 50);
        }
        if(this.forme.equals("TRIANGLE")){
                
               int s1X = posX + 50/2;
               int s1Y = posY;
               int s2X = posX + 50;
               int s2Y = posY + 50;
               int s3X = posX;
               int s3Y = posY + 50;
               
               int[] ptsX = {s1X, s2X, s3X};
               int[] ptsY = {s1Y, s2Y, s3Y};
               
               g.fillPolygon(ptsX, ptsY, 3);
        }
        if(this.forme.equals("ETOILE")){
               
               int s1X = posX + 50/2;
               int s1Y = posY;
               int s2X = posX + 50;
               int s2Y = posY + 50;                  
               g.drawLine(s1X, s1Y, s2X, s2Y);
               
               int s3X = posX;
               int s3Y = posY + 50/3;
               g.drawLine(s2X, s2Y, s3X, s3Y);
               
               int s4X = posX + 50;
               int s4Y = posY + 50/3;
               g.drawLine(s3X, s3Y, s4X, s4Y);               
                              
               int s5X = posX;
               int s5Y = posY + 50;
               g.drawLine(s4X, s4Y, s5X, s5Y);               
               g.drawLine(s5X, s5Y, s1X, s1Y);  
        }
        
    }
    
    /**
     * Méthode qui peint le morphing
     * @param g
     */
    private void drawMorph(Graphics g){
        //On incrémente le tour
        increment++;
        //On regarde si on doit réduire ou non
        if(drawSize >= 50)reduce = true;
        if(drawSize <= 10)reduce = false;
        
        if(reduce)
               drawSize = drawSize - getUsedSize();
        else
               drawSize = drawSize + getUsedSize();
        
        if(this.forme.equals("ROND")){
               g.fillOval(posX, posY, drawSize, drawSize); 
        }
        if(this.forme.equals("CARRE") || this.forme.equals("CARRÉ")){
               g.fillRect(posX, posY, drawSize, drawSize);
        }
        if(this.forme.equals("TRIANGLE")){
                 
               int s1X = posX + drawSize/2;
               int s1Y = posY;
               int s2X = posX + drawSize;
               int s2Y = posY + drawSize;
               int s3X = posX;
               int s3Y = posY + drawSize;
               
               int[] ptsX = {s1X, s2X, s3X};
               int[] ptsY = {s1Y, s2Y, s3Y};
               
               g.fillPolygon(ptsX, ptsY, 3);
        }
        if(this.forme.equals("ETOILE")){
               
               int s1X = posX + drawSize/2;
               int s1Y = posY;
               int s2X = posX + drawSize;
               int s2Y = posY + drawSize;            
               g.drawLine(s1X, s1Y, s2X, s2Y);
               
               int s3X = posX;
               int s3Y = posY + drawSize/3;
               g.drawLine(s2X, s2Y, s3X, s3Y);
               
               int s4X = posX + drawSize;
               int s4Y = posY + drawSize/3;
               g.drawLine(s3X, s3Y, s4X, s4Y);               
                              
               int s5X = posX;
               int s5Y = posY + drawSize;
               g.drawLine(s4X, s4Y, s5X, s5Y);               
               g.drawLine(s5X, s5Y, s1X, s1Y);  
        }
        
        
    }
    
    /**
     * Méthode qui retourne le nombre à retrancher ou ajouter pour le morphing
     * @return res
     */
    private int getUsedSize(){
        int res = 0;
        //Si le nombre de tours est 10
        //On réinitialise l'incrément et on retourne 1
        if(increment / 10 == 1){
               increment = 0;
               res = 1;
        }       
        return res;
    }
    
    public int getDrawSize(){
        return drawSize;
    }
    
    public boolean isMorph(){
        return morph;
    }
    
    public void setMorph(boolean bool){
        this.morph = bool;
        //On réinitialise la taille
        drawSize = 50;
    }
    
    public void setForme(String form){
        this.forme = form.toUpperCase();
    }
    
    public int getPosX() {
            return posX;
    }
 
    public void setPosX(int posX) {
            this.posX = posX;
    }
 
    public int getPosY() {
            return posY;
    }
 
    public void setPosY(int posY) {
            this.posY = posY;
    }
    
}

Fenetre.java



Code : Java -
  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
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
 
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.KeyStroke;
 
public class Fenetre extends JFrame{
 
        private Panneau pan = new Panneau();
    private JPanel container = new JPanel();
    private int compteur = 0;
    private boolean animated = true;
    private boolean backX, backY;
    private int x,y ;
    private Thread t;
    
    
 
    //***********************************************************
    //                 La déclaration pour le menu de la JMenuBar
    //***********************************************************
    private JMenuBar menuBar = new JMenuBar();
    
    private JMenu animation = new JMenu("Animation"),
               forme = new JMenu("Forme"),
               typeForme = new JMenu("Type de forme"),
               aPropos = new JMenu("À propos");
    
    private JMenuItem  lancer = new JMenuItem("Lancer l'animation"),
                                       arreter = new JMenuItem("Arrêter l'animation"),
                                       quitter = new JMenuItem("Quitter"),
                                       aProposItem = new JMenuItem("?");
            
    private JCheckBoxMenuItem morph = new JCheckBoxMenuItem("Morphing");
    private JRadioButtonMenuItem      carre = new JRadioButtonMenuItem("Carré"),
                                                              rond = new JRadioButtonMenuItem("Rond"),
                                                              triangle = new JRadioButtonMenuItem("Triangle"),
                                                              etoile = new JRadioButtonMenuItem("Etoile");
                                                              
    private ButtonGroup bg = new ButtonGroup();
    
    //***********************************************************
    //                 La déclaration pour le menu contextuel 
    //***********************************************************
    private JPopupMenu jpm = new JPopupMenu();
    private JMenu background = new JMenu("Couleur de fond");
    private JMenu couleur = new JMenu("Couleur de la forme");
        
    private JMenuItem launch = new JMenuItem("Lancer l'animation");                      
    private JMenuItem stop = new JMenuItem("Arrêter l'animation");
    private JMenuItem  rouge = new JMenuItem("Rouge"),
                                          bleu = new JMenuItem("Bleu"),
                                          vert = new JMenuItem("Vert"),
                                          blanc = new JMenuItem("Blanc"),
                                          rougeBack = new JMenuItem("Rouge"),
                                          bleuBack = new JMenuItem("Bleu"),
                                          vertBack = new JMenuItem("Vert"),
                                          blancBack = new JMenuItem("Blanc");
 
    //***********************************************************
    //                         ON CRÉE DES LISTENER GLOBAUX
    //***********************************************************
    private StopAnimationListener stopAnimation = new StopAnimationListener();
    private StartAnimationListener startAnimation = new StartAnimationListener();
    private CouleurFondListener bgColor = new CouleurFondListener();
    private CouleurFormeListener frmColor = new CouleurFormeListener();
    //**********************************************************
    
    public Fenetre(){
           
            this.setTitle("Animation");
            this.setSize(300, 300);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.setLocationRelativeTo(null);
 
            container.setBackground(Color.white);
            container.setLayout(new BorderLayout());
            
            //On initialise le menu stop
            stop.setEnabled(false);
            //On affecte les écouteurs
            stop.addActionListener(stopAnimation);
               launch.addActionListener(startAnimation);
            
               //On affecte les écouteurs aux points de menu
               rouge.addActionListener(frmColor);
               bleu.addActionListener(frmColor);
               vert.addActionListener(frmColor);
               blanc.addActionListener(frmColor);
               
               rougeBack.addActionListener(bgColor);
               bleuBack.addActionListener(bgColor);
               vertBack.addActionListener(bgColor);
               blancBack.addActionListener(bgColor);
               //On crée et on passe l'écouteur pour afficher le menu contextuel
               //Création d'une implémentation de MouseAdapter
               //avec redéfinition de la méthode adéquate
            pan.addMouseListener(new MouseAdapter(){
               public void mouseReleased(MouseEvent event){
                       //Seulement s'il s'agit d'un clic droit
                       if(event.isPopupTrigger())
                       {                              
                               background.add(blancBack);
                               background.add(rougeBack);
                               background.add(bleuBack);
                               background.add(vertBack);
                               
                               couleur.add(blanc);
                               couleur.add(rouge);
                               couleur.add(bleu);
                               couleur.add(vert);
                                                              
                               jpm.add(launch);
                               jpm.add(stop);
                               jpm.add(couleur);
                               jpm.add(background);
                               
                               //La méthode qui va afficher le menu
                               jpm.show(pan, event.getX(), event.getY());
                       }
               }
            });
            
            container.add(pan, BorderLayout.CENTER);
            
            this.setContentPane(container);
            this.initMenu();
            this.setVisible(true);            
                        
    }
    
 
        
    private void initMenu(){
        //Menu animation
        //****************************
        
        //Ajout du listener pour lancer l'animation
        //ATTENTION LE LISTENER EST GLOBAL ! ! ! ! 
        //-----------------------------------------------
        lancer.addActionListener(startAnimation);
        //On attribut l'accélerateur c
        lancer.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L,
                                                                                            KeyEvent.CTRL_MASK));
        animation.add(lancer);
        
        //Ajout du listener pour arrêter l'animation
        //LISTENER À CHANGER ICI AUSSI
        //--------------------------------------------
        arreter.addActionListener(stopAnimation);
        arreter.setEnabled(false);
        arreter.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A,
                                                                                            KeyEvent.CTRL_DOWN_MASK + KeyEvent.SHIFT_DOWN_MASK));
        animation.add(arreter);
        
        animation.addSeparator();
        quitter.addActionListener(new ActionListener(){
               public void actionPerformed(ActionEvent event){
                       System.exit(0);
               }
        });
        animation.add(quitter);
        
        //Menu forme
        
        bg.add(carre);
        bg.add(triangle);
        bg.add(rond);
        bg.add(etoile);
        
        //On crée un nouvel écouteur, inutile de créer 4 instances différentes
        FormeListener fl = new FormeListener();
        carre.addActionListener(fl);
        rond.addActionListener(fl);
        triangle.addActionListener(fl);
        etoile.addActionListener(fl);
        
        typeForme.add(rond);
        typeForme.add(carre);          
        typeForme.add(triangle);
        typeForme.add(etoile);
        
        rond.setSelected(true);
        
        forme.add(typeForme);
        
        //Ajout du listener pour le morphing
        morph.addActionListener(new MorphListener());
        forme.add(morph);
        
        //menu à propos
        
        //Ajout de ce que doit faire le "?"
        aProposItem.addActionListener(new ActionListener(){
                       public void actionPerformed(ActionEvent arg0) {
                               JOptionPane jop = new JOptionPane();
                               ImageIcon img = new ImageIcon("images/cysboy.gif");
                               
                               String mess = "Merci ! \n J'espère que vous vous amusez bien ! \n";
                               mess += "Je crois qu'il est temps d'ajouter des accélérateurs et des mnémoniques dans tout ça...\n";
                               mess += "\n Allez, GO les ZérOs !";
                               
                               jop.showMessageDialog(null, mess, "À propos", JOptionPane.INFORMATION_MESSAGE, img);
                               
                       }                             
        });
        aPropos.add(aProposItem);
        
        //Ajout des menus dans la barre de menus
        animation.setMnemonic('A');
        menuBar.add(animation);
        
        forme.setMnemonic('F');
        menuBar.add(forme);
        
        aPropos.setMnemonic('P');
        menuBar.add(aPropos);
        
        //Ajout de la barre de menus sur la fenêtre
        this.setJMenuBar(menuBar);
    }
    
        private void go(){
               x = pan.getPosX();
               y = pan.getPosY();
        while(this.animated){
               //System.out.println("OK");
               //Si le mode morphing est activé, on utilise la taille actuelle de la forme
               if(pan.isMorph())
               {
                       if(x < 1)backX = false;
                    if(x > pan.getWidth() - pan.getDrawSize())backX = true;               
                    if(y < 1)backY = false;
                    if(y > pan.getHeight() - pan.getDrawSize())backY = true;
               }
               //Sinon, comme d'habitude
               else
               {
                       if(x < 1)backX = false;
                    if(x > pan.getWidth()-50)backX = true;               
                    if(y < 1)backY = false;
                    if(y > pan.getHeight()-50)backY = true;
               }  
            
               if(!backX)pan.setPosX(++x);
            else pan.setPosX(--x);
            if(!backY) pan.setPosY(++y);
            else pan.setPosY(--y);
            pan.repaint();
 
            try {
                    Thread.sleep(3);
            } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
            }
        }       
        }
        
        /**
         * Écouteur du menu Lancer
         * @author 
         */
        public class StartAnimationListener implements ActionListener{
 
               public void actionPerformed(ActionEvent arg0) {
                       
                       JOptionPane jop = new JOptionPane();                  
                       int option = jop.showConfirmDialog(null, "Voulez-vous lancer l'animation ?", "Lancement de l'animation", JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE);
                       
                       if(option == JOptionPane.OK_OPTION)
                       {
                               lancer.setEnabled(false);
                               arreter.setEnabled(true);
                               
                               //ON AJOUTE L'INSTRUCTION POUR LE MENU CONTEXTUEL
                               //************************************************
                               launch.setEnabled(false);
                               stop.setEnabled(true);
                               
                               animated = true;
                               t = new Thread(new PlayAnimation());
                               t.start();                     
                       }
               }              
        }
        
        /**
         * Écouteur du menu Quitter
         * @author CHerby
         */
        class StopAnimationListener  implements ActionListener{
 
               public void actionPerformed(ActionEvent e) {
                       
                       JOptionPane jop = new JOptionPane();                  
                       int option = jop.showConfirmDialog(null, "Voulez-vous arrêter l'animation ?", "Arrêt de l'animation", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
                       
                       if(option != JOptionPane.NO_OPTION && option != JOptionPane.CANCEL_OPTION && option != JOptionPane.CLOSED_OPTION)
                       {
                               animated = false;
                               //On remplace nos boutons par nos JMenuItem
                               lancer.setEnabled(true);
                               arreter.setEnabled(false);
 
                               //ON AJOUTE L'INSTRUCTION POUR LE MENU CONTEXTUEL
                               //************************************************
                               launch.setEnabled(true);
                               stop.setEnabled(false);
                       }
               }              
        }       
        
        /**
         * Lance le thread.
         * @author CHerby
         */
        class PlayAnimation implements Runnable{
               public void run() {
                       go();                  
               }              
        }       
        
        /**
         * Écoute les menus forme
         * @author CHerby
         */
        class FormeListener implements ActionListener{
               public void actionPerformed(ActionEvent e) {
                       pan.setForme(((JRadioButtonMenuItem)e.getSource()).getText());
               }              
        }
        
        /**
         * Écoute le menu Morphing
         * @author CHerby
         */
        class MorphListener implements ActionListener{
               public void actionPerformed(ActionEvent e) {
                       //Si la case est cochée, activation du mode morphing
                       if(morph.isSelected())pan.setMorph(true);
                       //Sinon rien !
                       else pan.setMorph(false);
               }              
        }
        
        //************************************************************
        //             CLASSE QUI VONT ÉCOUTER LE CHANGEMENT DE COULEURS
        //************************************************************
        
        /**
         * Écoute le changement de couleur du fond
         */
        class CouleurFondListener implements ActionListener{
               public void actionPerformed(ActionEvent e) {
                       
                       if(e.getSource() == vertBack)
                               pan.setCouleurFond(Color.green);
                       else if (e.getSource() == bleuBack)
                               pan.setCouleurFond(Color.blue);
                       else if(e.getSource() == rougeBack)
                               pan.setCouleurFond(Color.red);
                       else
                               pan.setCouleurFond(Color.white);
               }
        }
        
        /**
         * Écoute le changement de couleur du fond
         */
        class CouleurFormeListener implements ActionListener{
               public void actionPerformed(ActionEvent e) {
                       if(e.getSource() == vert)
                               pan.setCouleurForme(Color.green);
                       else if (e.getSource() == bleu)
                               pan.setCouleurForme(Color.blue);
                       else if(e.getSource() == rouge)
                               pan.setCouleurForme(Color.red);
                       else
                               pan.setCouleurForme(Color.white);
               }
        }
        
}


Et voici quelques résultats obtenus :










Vous constatez que les menus et les menus contextuels peuvent être très utiles et très ergonomiques !
Ils sont relativement simples à utiliser et à implémenter.
Mais vous aurez sans doute remarqué qu'il y a toujours un clic superflu, qu'il s'agisse d'un menu ou d'un menu contextuel : il faut au moins un clic pour afficher le contenu d'un menu (sauf cas avec accélérateur).

Pour contrer ce genre de chose, il existe un outil très puissant : la barre d'outils !

Les barres d'outils

Voici un exemple de barre d'outils :


Vous voyez en rose la barre de menus et en vert la barre d'outils.
En fait, pour faire simple, la barre d'outils sert à effectuer des actions présentes dans le menu mais sans avoir à chercher dans celui-ci ou à mémoriser le raccourci clavier (accélérateur). Elle permet donc de pouvoir faire des actions rapides.

Elle est généralement composée de multitudes de boutons sur lesquels est apposée une image symbolisant l'action que ce bouton peut effectuer.

Pour créer et utiliser une barre d'outils, nous allons utiliser l'objet JToolBar.
Je vous rassure tout de suite, cet objet fonctionne comme un menu classique, à la différence près que celui-ci prend des boutons (JButton).
Il n'y a pas d'endroit spécifique pour incorporer votre barre d'outils, il faudra l'expliciter lors de sa création !


Il nous faut, tout d'abord, des images à mettre sur nos boutons... J'en ai fait de toutes simples :
Vous devez avoir une idée de ce que nous allons mettre dans notre barre d'outils... 

Concernant les actions à gérer, pour le lancement de l'animation et l'arrêt, il faudra penser à éditer le comportement des boutons de la barre d'outils, comme fait pour les deux actions du menu contextuel...

Concernant les boutons pour les formes, c'est un peu plus délicat.
Les autres composants pouvant éditer la forme de notre animation étaient des boutons radios. Or, ici, nous avons des boutons standards.
Hormis le fait qu'il va falloir une instance précise de la classe FormeListener, nous allons devoir modifier un peu son comportement...

Nous devrons savoir si l'action vient d'un bouton radio du menu ou d'un bouton de la barre d'outils...
Ça m'a l'air compliqué, tout ça !


En fait, non, et ceci grâce à l'objet ActionEvent. Nous allons pouvoir connaître le déclencheur de l'action ! Nous n'allons pas tester tous les boutons radio un par un... Le système utilisé jusque là, pour ces composants, était très bien.
Non, nous allons juste voir si celui qui a déclenché l'action est un JRadioButtonMenuItem ou non et, dans ce cas, nous testerons nos boutons...
Comment savoir ça ?

Rappelez-vous le chapitre sur la réflexivité !
La méthode getSource() nous retourne un objet, il est donc possible de connaître sa classe avec la méthode getClass() et donc, le nom de celle-ci avec la méthode getName() ...
Il va falloir qu'on pense à mettre à jour le bouton radio sélectionné dans le menu, alors ?

Tout à fait !
Je vois que vous commencez à penser événementiel !
Et là, pour votre plus grand plaisir, j'ai une astuce qui ne marche pas mal du tout : il suffit, lors du clic sur un bouton de la barre d'outils, de déclencher l'événement sur le bouton radio correspondant !
On serait curieux de savoir comment tu fais ça !

Dans la classe AbstractButton, dont héritent tous les boutons, il y a la méthode doClick() .
Cette méthode déclenche un événement identique à un vrai clic de souris sur le composant ! Donc, plutôt que de gérer la même façon de faire à deux endroits, nous allons rediriger l'action sur un autre composant...

Vous avez toutes les cartes pour faire votre barre d'outils.
N'oubliez pas que vous devez spécifier sa place sur le conteneur principal !

Bon, faites des tests, comparez, codez, effacez mais, au final, vous devriez avoir quelque chose comme ça :

Code : Java -
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
 
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
 
public class Fenetre extends JFrame{
 
        private Panneau pan = new Panneau();
    private JPanel container = new JPanel();
    private int compteur = 0;
    private boolean animated = true;
    private boolean backX, backY;
    private int x,y ;
    private Thread t;
    
    
 
    //***********************************************************
    //                 La déclaration pour le menu de la JMenuBar
    //***********************************************************
    private JMenuBar menuBar = new JMenuBar();
    
    private JMenu animation = new JMenu("Animation"),
               forme = new JMenu("Forme"),
               typeForme = new JMenu("Type de forme"),
               aPropos = new JMenu("À propos");
    
    private JMenuItem  lancer = new JMenuItem("Lancer l'animation"),
                                       arreter = new JMenuItem("Arrêter l'animation"),
                                       quitter = new JMenuItem("Quitter"),
                                       aProposItem = new JMenuItem("?");
            
    private JCheckBoxMenuItem morph = new JCheckBoxMenuItem("Morphing");
    private JRadioButtonMenuItem      carre = new JRadioButtonMenuItem("Carré"),
                                                              rond = new JRadioButtonMenuItem("Rond"),
                                                              triangle = new JRadioButtonMenuItem("Triangle"),
                                                              etoile = new JRadioButtonMenuItem("Etoile");
                                                              
    private ButtonGroup bg = new ButtonGroup();
    
    //***********************************************************
    //                 La déclaration pour le menu contextuel 
    //***********************************************************
    private JPopupMenu jpm = new JPopupMenu();
    private JMenu background = new JMenu("Couleur de fond");
    private JMenu couleur = new JMenu("Couleur de la forme");
        
    private JMenuItem launch = new JMenuItem("Lancer l'animation");                         
    private JMenuItem stop = new JMenuItem("Arrêter l'animation");
    private JMenuItem  rouge = new JMenuItem("Rouge"),
                                          bleu = new JMenuItem("Bleu"),
                                          vert = new JMenuItem("Vert"),
                                          blanc = new JMenuItem("Blanc"),
                                          rougeBack = new JMenuItem("Rouge"),
                                          bleuBack = new JMenuItem("Bleu"),
                                          vertBack = new JMenuItem("Vert"),
                                          blancBack = new JMenuItem("Blanc");
 
    //***********************************************************
    //                         ON CRÉE DES LISTENER GLOBAUX
    //***********************************************************
    private StopAnimationListener stopAnimation = new StopAnimationListener();
    private StartAnimationListener startAnimation = new StartAnimationListener();
    private CouleurFondListener bgColor = new CouleurFondListener();
    private CouleurFormeListener frmColor = new CouleurFormeListener();
    //**********************************************************
    
    
    //Création de notre barre d'outils
    private JToolBar toolBar = new JToolBar();
    
    //Les boutons
    private JButton    play = new JButton(new ImageIcon("images/play.jpg")),
                                      cancel = new JButton(new ImageIcon("images/stop.jpg")),
                                      square = new JButton(new ImageIcon("images/carré.jpg")),
                                      tri = new JButton(new ImageIcon("images/triangle.jpg")),
                                      circle = new JButton(new ImageIcon("images/rond.jpg")),
                                      star = new JButton(new ImageIcon("images/étoile.jpg"));
    
    private Color fondBouton = Color.white;
    private FormeListener fListener = new FormeListener();
    
    public Fenetre(){
           
            this.setTitle("Animation");
            this.setSize(400, 300);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.setLocationRelativeTo(null);
 
            container.setBackground(Color.white);
            container.setLayout(new BorderLayout());
            
            //On initialise le menu stop
            stop.setEnabled(false);
            //On affecte les écouteurs
            stop.addActionListener(stopAnimation);
               launch.addActionListener(startAnimation);
            
               //On affecte les écouteurs aux points de menus
               rouge.addActionListener(frmColor);
               bleu.addActionListener(frmColor);
               vert.addActionListener(frmColor);
               blanc.addActionListener(frmColor);
               
               rougeBack.addActionListener(bgColor);
               bleuBack.addActionListener(bgColor);
               vertBack.addActionListener(bgColor);
               blancBack.addActionListener(bgColor);
                //On crée et on passe l'écouteur pour afficher le menu contextuel
               //Création d'une implémentation de MouseAdapter
               //avec redéfinition de la méthode adéquate
            pan.addMouseListener(new MouseAdapter(){
               public void mouseReleased(MouseEvent event){
                       //Seulement s'il s'agit d'un clic droit
                       if(event.isPopupTrigger())
                       {                              
                               background.add(blancBack);
                               background.add(rougeBack);
                               background.add(bleuBack);
                               background.add(vertBack);
                               
                               couleur.add(blanc);
                               couleur.add(rouge);
                               couleur.add(bleu);
                               couleur.add(vert);
                                                              
                               jpm.add(launch);
                               jpm.add(stop);
                               jpm.add(couleur);
                               jpm.add(background);
                               
                               //La méthode qui va afficher le menu
                               jpm.show(pan, event.getX(), event.getY());
                       }
               }
            });
            
            container.add(pan, BorderLayout.CENTER);
            
            this.setContentPane(container);
            this.initMenu();
            this.initToolBar();
            this.setVisible(true);            
                        
    }
    
 
    private void initToolBar(){
        
        this.cancel.setEnabled(false);
        this.cancel.addActionListener(stopAnimation);
        this.cancel.setBackground(fondBouton);
        this.play.addActionListener(startAnimation);
        this.play.setBackground(fondBouton);
        
        this.toolBar.add(play);
        this.toolBar.add(cancel);
        this.toolBar.addSeparator();
        
        //Ajout des Listeners
        this.circle.addActionListener(fListener);
        this.circle.setBackground(fondBouton);
        this.toolBar.add(circle);
        
        this.square.addActionListener(fListener);
        this.square.setBackground(fondBouton);
        this.toolBar.add(square);
        
        this.tri.setBackground(fondBouton);
        this.tri.addActionListener(fListener);
        this.toolBar.add(tri);
        
        this.star.setBackground(fondBouton);
        this.star.addActionListener(fListener);
        this.toolBar.add(star);
        
        this.add(toolBar, BorderLayout.NORTH);
        
    }
    
        
    private void initMenu(){
        //Menu animation
        //****************************
        
        //Ajout du listener pour lancer l'animation
        //ATTENTION LE LISTENER EST GLOBAL ! ! ! ! 
        //-----------------------------------------------
        lancer.addActionListener(startAnimation);
        //On attribue l'accélerateur c
        lancer.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L,
                                                                                            KeyEvent.CTRL_MASK));
        animation.add(lancer);
        
        //Ajout du listener pour arrêter l'animation
        //LISTENER À CHANGER ICI AUSSI
        //--------------------------------------------
        arreter.addActionListener(stopAnimation);
        arreter.setEnabled(false);
        arreter.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A,
                                                                                            KeyEvent.CTRL_DOWN_MASK + KeyEvent.SHIFT_DOWN_MASK));
        animation.add(arreter);
        
        animation.addSeparator();
        quitter.addActionListener(new ActionListener(){
               public void actionPerformed(ActionEvent event){
                       System.exit(0);
               }
        });
        animation.add(quitter);
        
        //Menu forme
        
        bg.add(carre);
        bg.add(triangle);
        bg.add(rond);
        bg.add(etoile);
        
        //On crée un nouvel écouteur, inutile de créer 4 instances différentes
        
        carre.addActionListener(fListener);
        rond.addActionListener(fListener);
        triangle.addActionListener(fListener);
        etoile.addActionListener(fListener);
        
        typeForme.add(rond);
        typeForme.add(carre);          
        typeForme.add(triangle);
        typeForme.add(etoile);
        
        rond.setSelected(true);
        
        forme.add(typeForme);
        
        //Ajout du listener pour le morphing
        morph.addActionListener(new MorphListener());
        forme.add(morph);
        
        //menu à propos
        
        //Ajout de ce que doit faire le "?"
        aProposItem.addActionListener(new ActionListener(){
                       public void actionPerformed(ActionEvent arg0) {
                               JOptionPane jop = new JOptionPane();
                               ImageIcon img = new ImageIcon("images/cysboy.gif");
                               
                               String mess = "Merci ! \n J'espère que vous vous amusez bien ! \n";
                               mess += "Je crois qu'il est temps d'ajouter des accélérateurs et des mnémoniques dans tout ça...\n";
                               mess += "\n Allez, GO les ZérOs !";
                               
                               jop.showMessageDialog(null, mess, "À propos", JOptionPane.INFORMATION_MESSAGE, img);
                               
                       }                             
        });
        aPropos.add(aProposItem);
        
        //Ajout des menus dans la barre de menus
        animation.setMnemonic('A');
        menuBar.add(animation);
        
        forme.setMnemonic('F');
        menuBar.add(forme);
        
        aPropos.setMnemonic('P');
        menuBar.add(aPropos);
        
        //Ajout de la barre de menus sur la fenêtre
        this.setJMenuBar(menuBar);
    }
    
        private void go(){
               x = pan.getPosX();
               y = pan.getPosY();
        while(this.animated){
               //System.out.println("OK");
               //Si le mode morphing est activé, on utilise la taille actuelle de la forme
               if(pan.isMorph())
               {
                       if(x < 1)backX = false;
                    if(x > pan.getWidth() - pan.getDrawSize())backX = true;               
                    if(y < 1)backY = false;
                    if(y > pan.getHeight() - pan.getDrawSize())backY = true;
               }
               //Sinon, comme d'habitude
               else
               {
                       if(x < 1)backX = false;
                    if(x > pan.getWidth()-50)backX = true;               
                    if(y < 1)backY = false;
                    if(y > pan.getHeight()-50)backY = true;
               }  
            
               if(!backX)pan.setPosX(++x);
            else pan.setPosX(--x);
            if(!backY) pan.setPosY(++y);
            else pan.setPosY(--y);
            pan.repaint();
 
            try {
                    Thread.sleep(3);
            } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
            }
        }       
        }
        
        /**
         * Écouteur du menu Lancer
         * @author CHerby
         */
        public class StartAnimationListener implements ActionListener{
 
               public void actionPerformed(ActionEvent arg0) {
                       
                       JOptionPane jop = new JOptionPane();                  
                       int option = jop.showConfirmDialog(null, "Voulez-vous lancer l'animation ?", "Lancement de l'animation", JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE);
                       
                       if(option == JOptionPane.OK_OPTION)
                       {
                               lancer.setEnabled(false);
                               arreter.setEnabled(true);
                               
                               //ON AJOUTE L'INSTRUCTION POUR LE MENU CONTEXTUEL
                               //************************************************
                               launch.setEnabled(false);
                               stop.setEnabled(true);
                               
                               play.setEnabled(false);
                               cancel.setEnabled(true);
                               
                               animated = true;
                               t = new Thread(new PlayAnimation());
                               t.start();                     
                       }
               }              
        }
        
        /**
         * Écouteur du menu Quitter
         * @author CHerby
         */
        class StopAnimationListener  implements ActionListener{
 
               public void actionPerformed(ActionEvent e) {
                       
                       
                       JOptionPane jop = new JOptionPane();                  
                       int option = jop.showConfirmDialog(null, "Voulez-vous arrêter l'animation ?", "Arrêt de l'animation", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
                       
                       if(option != JOptionPane.NO_OPTION && option != JOptionPane.CANCEL_OPTION && option != JOptionPane.CLOSED_OPTION)
                       {
                               animated = false;
                               //On remplace nos bouton par nous MenuItem
                               lancer.setEnabled(true);
                               arreter.setEnabled(false);
 
                               //ON AJOUTE L'INSTRUCTION POUR LE MENU CONTEXTUEL
                               //************************************************
                               launch.setEnabled(true);
                               stop.setEnabled(false);
                               
                               play.setEnabled(true);
                               cancel.setEnabled(false);
                               
                       }
               }              
        }       
        
        /**
         * Lance le thread.
         * @author CHerby
         */
        class PlayAnimation implements Runnable{
               public void run() {
                       go();                  
               }              
        }       
        
        /**
         * Écoute les menus forme
         * @author CHerby
         */
        class FormeListener implements ActionListener{
               public void actionPerformed(ActionEvent e) {
                       
                       //Si l'action vient d'un bouton radio du menu 
                       if(e.getSource().getClass().getName().equals("javax.swing.JRadioButtonMenuItem"))
                               pan.setForme(((JRadioButtonMenuItem)e.getSource()).getText());
                       else{
                               if(e.getSource() == square){
                                      carre.doClick();
                               }
                               else if(e.getSource() == tri){
                                      triangle.doClick();
                               }
                               else if(e.getSource() == star){
                                      etoile.doClick();
                               }
                               else{
                                      rond.doClick();
                               }
                       }
               }              
        }
        
        /**
         * Écoute le menu Morphing
         * @author CHerby
         */
        class MorphListener implements ActionListener{
               public void actionPerformed(ActionEvent e) {
                       //Si la case est cochée, activation du mode morphing
                       if(morph.isSelected())pan.setMorph(true);
                       //Sinon rien !
                       else pan.setMorph(false);
               }              
        }
        
        //************************************************************
        //             CLASSES QUI VONT ECOUTER LE CHANGEMENT DE COULEURS
        //************************************************************
        
        /**
         * Écoute le changement de couleur du fond
         */
        class CouleurFondListener implements ActionListener{
               public void actionPerformed(ActionEvent e) {
                       
                       if(e.getSource() == vertBack)
                               pan.setCouleurFond(Color.green);
                       else if (e.getSource() == bleuBack)
                               pan.setCouleurFond(Color.blue);
                       else if(e.getSource() == rougeBack)
                               pan.setCouleurFond(Color.red);
                       else
                               pan.setCouleurFond(Color.white);
               }
        }
        
        /**
         * Écoute le changement de couleur du fond
         */
        class CouleurFormeListener implements ActionListener{
               public void actionPerformed(ActionEvent e) {
                       if(e.getSource() == vert)
                               pan.setCouleurForme(Color.green);
                       else if (e.getSource() == bleu)
                               pan.setCouleurForme(Color.blue);
                       else if(e.getSource() == rouge)
                               pan.setCouleurForme(Color.red);
                       else
                               pan.setCouleurForme(Color.white);
               }
        }
        
}


Vous devez obtenir une IHM ressemblant à ceci :


Elle n'est pas zolie, votre IHM, maintenant ?
Vous avez bien travaillé, surtout que je vous explique les grandes lignes mais vous avez une part de réflexion, à présent !
Eh oui, vous avez appris à penser en orienté objet, vous connaissez les grandes lignes de la programmation événementielle. Maintenant, ce ne sont juste que des points techniques spécifiques à acquérir comme l'utilisation de certains objets !

D'ailleurs, vous devez savoir une dernière chose : dans les barres d'outils comme celle-ci, vous pouvez mettre d'autres composants que des boutons (combo...).


Pour ceux qui l'auraient remarqué, la barre d'outils est déplaçable ! Si vous cliquez sur cette zone :


si vous laissez le clic appuyé et faites glisser votre souris vers la droite, la gauche ou encore le bas, vous pourrez voir un carré se déplacer :


Et lorsque vous relâchez les clics, votre barre à changé d'emplacement :




Elles sont fortes ces barres d'outils, tout de même !
Par contre, vous devez savoir que vous pouvez utiliser autre chose qu'un composant sur une barre d'outils...

Utiliser les actions abstraites

Nous avons vu, plus haut, comment centraliser les actions sur différents composants.
Vous devez savoir qu'il existe une classe abstraite qui permet de gérer ce genre de chose car elle peut s'adapter à beaucoup de composants (en général à ceux qui ne font qu'une action comme un bouton, une case à cocher et non une liste...).

Le but de cette classe est d'attribuer automatiquement une action à un ou plusieurs composants. Le principal avantage de cette façon de faire réside dans le fait que plusieurs composants travaillent avec une implémentation de la classe AbstractAction, mais le gros inconvénient réside dans le fait que vous devrez programmer une implémentation par action :
  • une action pour la couleur de la forme en rouge ;
  • une action pour la couleur de la forme en bleu ;
  • une action pour la couleur de la forme en vert ;
  • une action pour la couleur du fond en rouge ;
  • une action pour la couleur du fond en bleu ;
  • ...


Ceci peut être très lourd à faire, mais après, je vous laisse juges d'utiliser telle ou telle façon selon vos besoins !

Voici comment s'implémente cette classe :

Code : Java -
 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
public class Fenetre extends JFrame{
 
   //Nous pouvons utiliser les actions abstraites directement dans un JButton
   private JButton bouton1 = new JButton(new RougeAction("ActionRouge", new ImageIcon("images/rouge.jpg"));
    
    //Ou créer un instance concrète
    private RougeAction rAct = new RougeAction("ActionRouge", new ImageIcon("images/rouge.jpg"));
    private JToolBar toolBar = new JToolBar();
 
    //...
 
    //Et le plus fort : UTILISER UNE INSTANCE D'ACTION DIRECTEMENT DANS UNE BARRE D'OUTILS
    private void initToolBar(){
        toolBar.add(rAct);
    }
 
    
 
   //...
 
   class RougeAction extends AbstractAction{
 
       //Constructeur avec le nom uniquement
       public RougeAction(String name){super(name);}
 
       //Le constructeur prend le nom et une icône en paramètre
       public RougeAction(String name, ImageIcon){super(name, img);}
 
       public void actionPerformed(ActionEvent){
           //Vous connaissez la marche à suivre
       }
   }
 
}


Vous pouvez voir que cela peut être très pratique. De plus, si vous ajoutez une action sur une barre d'outils, celle-ci crée automatiquement un bouton correspondant !
Ensuite, le choix d'utiliser les actions abstraites ou des implémentations de telle ou telle interface vous revient.

Nous pouvons d'ailleurs très bien appliquer ce principe au code de notre animation.

Voici ce que peut donner le code vu précédemment avec des implémentations de la classe AbstractAction :

Code : Java -
  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
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
 
import javax.swing.AbstractAction;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
 
public class ZFenetre extends JFrame{
 
        private Panneau pan = new Panneau();
    private JPanel container = new JPanel();
    private int compteur = 0;
    private boolean animated = true;
    private boolean backX, backY;
    private int x,y ;
    private Thread t;
   
   //Création des instances d'actions de forme
   private CarreAction cAction = new CarreAction("Carré", new ImageIcon("images/carré.jpg")); 
   private RondAction rAction = new RondAction("Rond",  new ImageIcon("images/rond.jpg"));
   private TriangleAction tAction = new TriangleAction("Triangle",  new ImageIcon("images/triangle.jpg"));
   private EtoileAction eAction = new EtoileAction("Etoile",  new ImageIcon("images/étoile.jpg"));
   
   //Création des instances d'actions de couleurs de forme
   private FormeRougeAction rfAction = new FormeRougeAction("Rouge");
   private FormeBleuAction bfAction = new FormeBleuAction("Bleu");
   private FormeVertAction vfAction = new FormeVertAction("Vert");
   private FormeBlancAction wfAction = new FormeBlancAction("Blanc");
   
   //Création des instances de couleurs de fond
   private FondRougeAction rFondAction = new FondRougeAction("Rouge");
   private FondBleuAction bFondAction = new FondBleuAction("Bleu");
   private FondVertAction vFondAction = new FondVertAction("Vert");
   private FondBlancAction wFondAction = new FondBlancAction("Blanc");
   
   //Création des instances d'actions pour le lancement et l'arrêt
   private LancerAction lAction = new LancerAction("Lancer l'animation",   new ImageIcon("images/play.jpg"));
   private ArretAction sAction = new ArretAction("Arrêter l'animation",   new ImageIcon("images/stop.jpg"));
   
   //***********************************************************
    //                 La déclaration pour le menu de la JMenuBar
    //***********************************************************
    private JMenuBar menuBar = new JMenuBar();
    
    private JMenu animation = new JMenu("Animation"),
               forme = new JMenu("Forme"),
               typeForme = new JMenu("Type de forme"),
               aPropos = new JMenu("À propos");
    
    private JMenuItem  lancer = new JMenuItem(lAction),
                                       arreter = new JMenuItem(sAction),
                                       quitter = new JMenuItem("Quitter"),
                                       aProposItem = new JMenuItem("?");
            
    private JCheckBoxMenuItem morph = new JCheckBoxMenuItem("Morphing");
    private JRadioButtonMenuItem      carre = new JRadioButtonMenuItem(cAction),
                                                              rond = new JRadioButtonMenuItem(rAction),
                                                              triangle = new JRadioButtonMenuItem(tAction),
                                                              etoile = new JRadioButtonMenuItem(eAction);
                                                              
    private ButtonGroup bg = new ButtonGroup();
    
    //***********************************************************
    //                 La déclaration pour le menu contextuel 
    //***********************************************************
    private JPopupMenu jpm = new JPopupMenu();
    private JMenu background = new JMenu("Couleur de fond");
    private JMenu couleur = new JMenu("Couleur de la forme");
        
    private JMenuItem launch = new JMenuItem(lAction);                              
    private JMenuItem stop = new JMenuItem(sAction);
    private JMenuItem  rouge = new JMenuItem(rfAction),
                                          bleu = new JMenuItem(bfAction),
                                          vert = new JMenuItem(vfAction),
                                          blanc = new JMenuItem(wfAction),
                                          rougeBack = new JMenuItem(rFondAction),
                                          bleuBack = new JMenuItem(bFondAction),
                                          vertBack = new JMenuItem(vFondAction),
                                          blancBack = new JMenuItem(wFondAction);
 
    
    
    //Création de notre barre d'outils
    private JToolBar toolBar = new JToolBar();
    
    //Les boutons
    private JButton    play = new JButton(lAction),
                                      cancel = new JButton(sAction),
                                      square = new JButton(cAction),
                                      tri = new JButton(tAction),
                                      circle = new JButton(rAction),
                                      star = new JButton(eAction);
    
    private Color fondBouton = Color.white;
    
    
    public ZFenetre(){
           
            this.setTitle("Animation");
            this.setSize(800, 600);
            this.setResizable(false);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.setLocationRelativeTo(null);
            
            container.setBackground(Color.white);
            container.setLayout(new BorderLayout());
            
            //On initialise le menu stop
            stop.setEnabled(false);
            
               //On crée et on passe l'écouteur pour afficher le menu contextuel
               //Création d'une implémentation de MouseAdapter
               //avec redéfinition de la méthode adéquate
            pan.addMouseListener(new MouseAdapter(){
               public void mouseReleased(MouseEvent event){
                       //Seulement s'il s'agit d'un clic droit
                       if(event.isPopupTrigger())
                       {                              
                               background.add(blancBack);
                               background.add(rougeBack);
                               background.add(bleuBack);
                               background.add(vertBack);
                               
                               couleur.add(blanc);
                               couleur.add(rouge);
                               couleur.add(bleu);
                               couleur.add(vert);
                                                              
                               jpm.add(launch);
                               jpm.add(stop);
                               jpm.add(couleur);
                               jpm.add(background);
                               
                               //La méthode qui va afficher le menu
                               jpm.show(pan, event.getX(), event.getY());
                       }
               }
            });
            
            container.add(pan, BorderLayout.CENTER);
            
            this.setContentPane(container);
            this.initMenu();
            this.initToolBar();
            this.setVisible(true);            
                        
    }
    
 
    private void initToolBar(){
        
        this.cancel.setEnabled(false);
        this.cancel.setBackground(fondBouton);
        this.play.setBackground(fondBouton);
        this.toolBar.setFont(new Font("Courier", Font.PLAIN, 0));
        
        this.toolBar.add(play);
        this.toolBar.add(cancel);
        this.toolBar.addSeparator();
        
        this.toolBar.add(rAction);
        this.toolBar.add(cAction);
        this.toolBar.add(tAction);
        this.toolBar.add(eAction);
        
        
        this.add(toolBar, BorderLayout.NORTH);
        
    }
    
        
    private void initMenu(){
        //Menu animation
        //****************************
        
        //Ajout du listener pour lancer l'animation
        //ATTENTION LE LISTENER EST GLOBAL ! ! ! ! 
        //-----------------------------------------------
        //On attribue l'accélerateur c
        lancer.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L,
                                                                                            KeyEvent.CTRL_MASK));
        animation.add(lancer);
        
        //Ajout du listener pour arrêter l'animation
        //LISTENER À CHANGER ICI AUSSI
        //--------------------------------------------
        arreter.setEnabled(false);
        arreter.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A,
                                                                                            KeyEvent.CTRL_DOWN_MASK + KeyEvent.SHIFT_DOWN_MASK));
        animation.add(arreter);
        
        animation.addSeparator();
        quitter.addActionListener(new ActionListener(){
               public void actionPerformed(ActionEvent event){
                       System.exit(0);
               }
        });
        animation.add(quitter);
        
        //Menu forme
        
        bg.add(carre);
        bg.add(triangle);
        bg.add(rond);
        bg.add(etoile);
        
        //On crée un nouvel écouteur, inutile de créer 4 instances différentes
        
        typeForme.add(rond);
        typeForme.add(carre);          
        typeForme.add(triangle);
        typeForme.add(etoile);
        
        rond.setSelected(true);
        
        forme.add(typeForme);
        
        //Ajout du listener pour le morphing
        morph.addActionListener(new MorphListener());
        forme.add(morph);
        
        //menu à propos
        
        //Ajout de ce que doit faire le "?"
        aProposItem.addActionListener(new ActionListener(){
                       public void actionPerformed(ActionEvent arg0) {
                               JOptionPane jop = new JOptionPane();
                               ImageIcon img = new ImageIcon("images/cysboy.gif");
                               
                               String mess = "Merci ! \n J'espère que vous vous amusez bien ! \n";
                               mess += "Je crois qu'il est temps d'ajouter des accélérateurs et des mnémoniques dans tout ça...\n";
                               mess += "\n Allez, GO les ZérOs !";
                              
                               jop.showMessageDialog(null, mess, "À propos", JOptionPane.INFORMATION_MESSAGE, img);
                               
                       }                             
        });
        aPropos.add(aProposItem);
        
        //Ajout des menus dans la barre de menus
        animation.setMnemonic('A');
        menuBar.add(animation);
        
        forme.setMnemonic('F');
        menuBar.add(forme);
        
        aPropos.setMnemonic('P');
        menuBar.add(aPropos);
        
        //Ajout de la barre de menus sur la fenêtre
        this.setJMenuBar(menuBar);
    }
    
        private void go(){
               x = pan.getPosX();
               y = pan.getPosY();
        while(this.animated){
               //System.out.println("OK");
               //Si le mode morphing est activé, on utilise la taille actuelle de la forme
               if(pan.isMorph())
               {
                       if(x < 1)backX = false;
                    if(x > pan.getWidth() - pan.getDrawSize())backX = true;               
                    if(y < 1)backY = false;
                    if(y > pan.getHeight() - pan.getDrawSize())backY = true;
               }
               //Sinon, comme d'habitude
               else
               {
                       if(x < 1)backX = false;
                    if(x > pan.getWidth()-50)backX = true;               
                    if(y < 1)backY = false;
                    if(y > pan.getHeight()-50)backY = true;
               }  
            
               if(!backX)pan.setPosX(++x);
            else pan.setPosX(--x);
            if(!backY) pan.setPosY(++y);
            else pan.setPosY(--y);
            pan.repaint();
 
            try {
                    Thread.sleep(3);
            } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
            }
        }       
        }
               
        /**
         * Lance le thread.
         * @author CHerby
         */
        class PlayAnimation implements Runnable{
               public void run() {
                       go();                  
               }              
        }       
        
        /**
         * Écoute le menu Morphing
         * @author CHerby
         */
        class MorphListener implements ActionListener{
               public void actionPerformed(ActionEvent e) {
                       //Si la case est cochée, activation du mode morphing
                       if(morph.isSelected())pan.setMorph(true);
                       //Sinon rien !
                       else pan.setMorph(false);
               }              
        }
 
        
        //*************************************************************
        //                     LES CLASSES D'ACTIONS POUR LA FORME
        //*************************************************************
        
        /**
         * Classe gérant le changement de la forme en carré
         * @author CHerby
         */
        class CarreAction extends AbstractAction{
               /**
                * Le constructeur prend le nom de l'icône en paramètre
                * @param name
                * @param img
                */
               public CarreAction(String name, ImageIcon img){
                       super(name, img);
               }
               /**
                * Celui-ci ne prend que le nom
                * @param name
                */
               public CarreAction(String name){
                       super(name);
               }
               
               /**
                * L'action effectuée
                */
               public void actionPerformed(ActionEvent e) {
                       pan.setForme("CARRE");
                       carre.setSelected(true);
               }              
        }
        
        //*************************************************************
        
        class RondAction extends AbstractAction{
               public RondAction(String name, ImageIcon img){
                       super(name, img);
               }
               public void actionPerformed(ActionEvent arg0) {
                       pan.setForme("ROND");
                       rond.setSelected(true);
               }              
        }
 
        //*************************************************************
        
        class TriangleAction extends AbstractAction{
               public TriangleAction(String name, ImageIcon img){
                       super(name, img);
               }
               public void actionPerformed(ActionEvent arg0) {
                       pan.setForme("TRIANGLE");
                       triangle.setSelected(true);
               }              
        }
        
        //*************************************************************
        
        class EtoileAction extends AbstractAction{
               public EtoileAction(String name, ImageIcon img){
                       super(name, img);
               }
               public void actionPerformed(ActionEvent arg0) {
                       pan.setForme("ETOILE");
                       etoile.setSelected(true);
               }              
        }
        
        //*************************************************************
        //                             ACTIONS POUR LES COULEURS DE FOND     
        //*************************************************************
        
        
        class FondRougeAction extends AbstractAction{
               public FondRougeAction(String name){
                       super(name);
               }
               public void actionPerformed(ActionEvent arg0) {
                       pan.setCouleurFond(Color.red);
               }              
        }
 
        //*************************************************************
        
        class FondBleuAction extends AbstractAction{
               public FondBleuAction(String name){
                       super(name);
               }
               public void actionPerformed(ActionEvent arg0) {
                       pan.setCouleurFond(Color.blue);
               }              
        }
 
        //*************************************************************
        
        class FondVertAction extends AbstractAction{
               public FondVertAction(String name){
                       super(name);
               }
               public void actionPerformed(ActionEvent arg0) {
                       pan.setCouleurFond(Color.green);
               }              
        }
 
        //*************************************************************
        
        class FondBlancAction extends AbstractAction{
               public FondBlancAction(String name){
                       super(name);
               }
               public void actionPerformed(ActionEvent arg0) {
                       pan.setCouleurFond(Color.white);
               }              
        }
        
 
        
 
        //*************************************************************
        //                     ACTIONS POUR LES COULEURS DE LA FORME 
        //*************************************************************
        
        
        class FormeRougeAction extends AbstractAction{
               public FormeRougeAction(String name){
                       super(name);
               }
               public void actionPerformed(ActionEvent arg0) {
                       pan.setCouleurForme(Color.red);
               }              
        }
 
        //*************************************************************
        
        class FormeBleuAction extends AbstractAction{
               public FormeBleuAction(String name){
                       super(name);
               }
               public void actionPerformed(ActionEvent arg0) {
                       pan.setCouleurForme(Color.blue);
               }              
        }
 
        //*************************************************************
        
        class FormeVertAction extends AbstractAction{
               public FormeVertAction(String name){
                       super(name);
               }
               public void actionPerformed(ActionEvent arg0) {
                       pan.setCouleurForme(Color.green);
               }              
        }
 
        //*************************************************************
        
        class FormeBlancAction extends AbstractAction{
               public FormeBlancAction(String name){
                       super(name);
               }
               public void actionPerformed(ActionEvent arg0) {
                       pan.setCouleurForme(Color.white);
               }              
        }
 
        
        
        
        //*************************************************************
        //                     ACTIONS POUR LE LANCEMENT/ARRÊT       
        //*************************************************************
        
        
        class ArretAction extends AbstractAction{
               public ArretAction(String name, ImageIcon img){
                       super(name, img);
               }
               public void actionPerformed(ActionEvent arg0) {
                       JOptionPane jop = new JOptionPane();                  
                       int option = jop.showConfirmDialog(null, "Voulez-vous arrêter l'animation ?", "Arrêt de l'animation", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
                       
                       if(option != JOptionPane.NO_OPTION && option != JOptionPane.CANCEL_OPTION && option != JOptionPane.CLOSED_OPTION)
                       {
                               animated = false;
                               //On remplace nos boutons par nos MenuItem
                               lancer.setEnabled(true);
                               arreter.setEnabled(false);
 
                               //ON AJOUTE L'INSTRUCTION POUR LE MENU CONTEXTUEL
                               //************************************************
                               launch.setEnabled(true);
                               stop.setEnabled(false);
                               
                               play.setEnabled(true);
                               cancel.setEnabled(false);
                               
                       }
               }              
        }
 
        //*************************************************************
        
        class LancerAction extends AbstractAction{
               public LancerAction(String name, ImageIcon img){
                       super(name, img);
               }
               public void actionPerformed(ActionEvent arg0) {
                       
                       JOptionPane jop = new JOptionPane();                  
                       int option = jop.showConfirmDialog(null, "Voulez-vous lancer l'animation ?", "Lancement de l'animation", JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE);
                       
                       if(option == JOptionPane.OK_OPTION)
                       {
                               lancer.setEnabled(false);
                               arreter.setEnabled(true);
                               
                               //ON AJOUTE L'INSTRUCTION POUR LE MENU CONTEXTUEL
                               //************************************************
                               launch.setEnabled(false);
                               stop.setEnabled(true);
                               
                               play.setEnabled(false);
                               cancel.setEnabled(true);
                               
                               animated = true;
                               t = new Thread(new PlayAnimation());
                               t.start();                     
                       }
               }              
        }
 
}


Vous pouvez voir que le code s'est un peu alourdi...
Mais, comme je vous le disais, c'est une question de choix et de conception.

Bon, je crois qu'un topo et un QCM vous attendent...

Ce qu'il faut retenir

  • L'objet pour mettre une barre de menu sur vos IHM swing est un JMenuBar.
  • Dans cet objet, vous pouvez mettre des objets JMenu afin de créer un menu déroulant.
  • L'objet cité ci-dessus accepte des objets JMenu, JMenuItem, JCheckBoxMenuItem et JRadioButtonMenuItem.
  • Afin d'interagir avec vos points de menu, vous pouvez utiliser une implémentation de l'interface ActionListener.
  • Pour faciliter l'accès aux menus de la barre de menus, vous pouvez ajouter des mnémoniques à ceux-ci.
  • L'ajout d'accélérateurs permet de déclencher des actions, le plus souvent, par des combinaisons de touches.
  • Afin de pouvoir récupérer les codes des touches du clavier, vous devrez utiliser un objet KeyStroke ainsi qu'un objet KeyEvent.
  • Les menus contextuels fonctionnent tout comme un menu normal, à la différence qu'il s'agit d'un objet JPopupMenu.
  • Vous devez toutefois spécifier sur quel composant doit s'afficher le menu contextuel.
  • La détection du clic droit se fait grâce à la méthode isPopupTrigger() de l'objet MouseEvent.
  • L'ajout d'une barre d'outils nécessite l'utilisation de l'objet JToolBar.
Vous avez encore appris beaucoup de choses dans ce chapitre...
Je vous rassure, vous n'êtes pas au bout de vos peines !

Il nous reste encore tant de choses à voir. D'ailleurs, vous vous demandez peut-être comment faire pour créer un menu "Enregistrer" ou encore "Enregistrer sous" ?

Avant de voir comment faire ceci, nous allons passer par un petit TP : L'ardoise mazique !


0 comments to "LECON 312"

Post a Comment

Powered by Blogger.

About This Blog

Aller au debut de la page