Previous Up Next

2  Où et comment gérer les événements?

Le but de cette partie est d’étudier les différentes manières de gérer l’événement de clic sur un bouton. Nous utiliserons une interface avec un bouton qui permet d’incrémenter la valeur d’un label.

Question 1. En utilisant la classe JFrame, le gestionnaire de placement BoxLayout, les classes JLabel et JButton, réalisez une interface similaire à celle présentée figure 1


Figure 1: Application incrémenter

JButton possède une méthode addActionListener qui lui permet de s’abonner à l’événement "clic sur le bouton de la souris". Le paramètre de cette méthode est un objet de type ActionListener. ActionListener est une interface qui doit être implémentée. La seule méthode à implémenter est la méthode actionPerformed qui est la méthode qui sera appelée quand un clic aura lieu.

Question 2. Ecrivez une classe ReponseAuClic qui implémente la méthode actionPerformed de l’interface ActionListener pour afficher "Clic sur le bouton" sur la console quand la méthode est appelée. Abonnez votre bouton à cette classe et vérifiez que le message s’affiche bien à l’écran à chaque fois que vous cliquez sur le bouton.

Nous souhaitons que la méthode actionPerformed modifie le texte du label. Pour que le listener puisse modifier cet objet, il est nécessaire de passer en paramètre du constructeur ReponseAuClic une référence de l’objet JLabel qu’il devra modifier.

Question 3. Modifier votre classe ReponseAuClic en ajoutant le JLabel en paramètre du contructeur et en modifiant la méthode actionPerformed pour récupérer et modifier le texte du label. Vous utiliserez la méthode getText() pour récupérer le texte du label et la méthode Integer.parseInt pour convertir la chaîne de caractères en entier. La méthode setText() permet de modifier le texte du label.

En suivant ce principe, l’écriture d’applications simples va demander l’écriture d’un nombre important de classes de listener, ce qui peut rapidement devenir difficile à gérer. On remarque aussi que certains listeners sont étroitement liés au composant source et ne seront probablement jamais réutilisés pour un autre composant. Une autre solution est d’utiliser les classes internes.

2.1  Classes internes

Depuis le JDK1.1, il est possible d’imbriquer les définitions de classes les unes dans les autres. Une classe définie à l’intérieur d’une autre est appelée classe interne. Cette classe est généralement déclarée privée pour limiter son accès à la classe englobante.
Cette façon de faire permet de simplifier l’écriture du listener car nous n’avons plus besoin de passer le JLabel en paramètre du constructeur. La classe privée a en effet accès aux membres, même privés, de la classe englobante.

Question 4. Ecrivez une classe FenetreIncrementer avec le JLabel déclaré comme membre privé. Reprenez et modifiez la classe ReponseAuClic écrite à la question précédente en l’incluant dans la classe FenetreIncrementer (vous la définirez comme classe privée).

La classe ReponseAuClic n’étant utilisée qu’une seule fois, il est possible de la définir directement à l’endroit où une instance de cette classe est nécessaire. Par ailleurs, puisque cette classe est amenée à n’être utilisée qu’une seule fois, il est même inutile de lui donner un nom explicite. Nous pouvons dans ce cas utiliser une classe interne anonyme.

2.2  Classes internes anonymes

Le mécanisme des classes internes anonymes est adapté au cas de figure où l’on a besoin à un instant donné d’une instance de classe, et on est certain de ne pas avoir à créer d’autres instances ailleurs, ni à référencer cette classe plus loin. Le mécanisme consiste à appeler le constructeur et à construire en même temps la classe. L’appel au constructeur ne nécessite pas le nom de la classe: on indique le nom de la classe héritée ou de l’interface implémentée par la classe interne anonyme.
Par exemple, la déclaration d’une classe interne anonyme pour la gestion du clic sur le bouton donne quelque chose comme ceci:

lebouton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { /** * Mise a jour du label */ } });

L’instruction new ActionListener() instancie un objet d’une classe qui n’a pas de nom, autrement dit est anonyme; dérive de Object; et implémente l’interface actionPerformed. L’instance a été créée en utilisant le constructeur par défaut, c’est-à-dire le constructeur sans paramètre.
De la même manière il est possible de créer des classes internes anonymes dérivées d’autres classes.
Pour éviter de rendre difficile la lecture du code, il est d’usage d’appeler une méthode de la classe englobante pour chaque méthode implémentée dans la classe anonyme:

lebouton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { /** * Mise a jour du label */ miseAJourDuLabel(e); } });

Question 5. Testez l’utilisation des classes internes anonymes dans votre exemple précédent.

Cette méthode de gestion des événements qui est utilisée dans les outils de génération d’interfaces comme NetBeans.

2.3  Les adapters

Pour fermer la fenêtre en cliquant sur le bouton de fermeture, nous avons vu précédemment qu’il est possible d’utiliser la méthode setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) afin de provoquer la fin de l’exécution du programme quand cet événement survient. Pour gérer soi même cet événement, il est possible d’écrire une classe qui implémente l’interface WindowListener avec la méthode windowClosing. L’inconvénient est que cette interface spécifie sept méthodes et nous souhaitons uniquement implémenter la méthode windowClosing.
Pour éviter d’avoir à implémenter six méthodes vides, Java fournit des classes d’implémentation par défaut des listeners. Ce sont les adapters. Les adapters implémentent des versions vides de toutes les méthodes de l’interface. Il nous suffit donc d’hériter de la classe WindowAdapter et de redéfinir seulement la méthode nécessaire.

Question 6. Ecrivez une classe FermetureFenetre, qui hérite de WindowAdapter, et qui redéfinit windowClosing pour afficher le message "Fenetre en cours de fermeture" avant de terminer l’exécution du programme par un System.exit(0).


Previous Up Next