Chapitre 8 Gestion des événements A. Nejeoui
Gestion des événements Introduction La gestion des événements est d'une importance fondamentale pour les programmes avec une interface graphique . Pour la mise en oeuvre des interfaces graphique, vous devez maîtriser la manière dont Java gère les événements. Ce chapitre explique comment fonctionne le modèle de gestion d'événement Java AWT . Vous verrez comment capturer les événements des différents composants de l'interface graphique. Vous verrez aussi comment travailler avec les classes internes "Inner Class" et les classes anonymes. Les points suivants serons traités dans ce chapitre: Définir un événement et la gestion d’un événement Écrire le code pour gérer un événement Définir le concept d’adaptateur Identifier les Principaux types d'événements Comprendre l’utilité de l’utilisation des classes internes et classes anonymes. 13.11.2017 Gestion des événements
Gestion des événements Puisqu'un composant est visible sur un écran, il est naturellement prédestiné à devenir la cible d'actions faites par l'utilisateur à l'aide de la souris, du clavier ou de tout autre organe de saisie disponible. Au moment où elle est détectée par le système d’exploitation, une action de l'utilisateur provoque la création par la machine Virtuelle Java d'un événement :C’est un objet décrivant la nature et les circonstances de cette action ; on dit que le composant qui en a été la cible de cette action est la source de l' événement en question. Toues les événement (awt) héritent de la classe java.awt.AWTEvent qui hérite de la classe java.util.EventObject. Quelques Méthodes : Public Object getSource () // méthode de la classe EventObject qui retourne la référence de l’objet source de l’événement 13.11.2017 Gestion des événements
Gestion des événements Exemple 13.11.2017 Gestion des événements
Gestion des événements Types d’événements 13.11.2017 Gestion des événements
Principaux types d'événements Chaque type d'événement correspond a une interface d'auditeurs. Les principales sont les suivantes : 1 MouseListener 2 MouseMotionListener and MouseWeelListener 3 KeyListener 4 FocusListener 5 ActionListener 6 ItemListener 7 AdjustmentListener 8 TextListener 9 WindowListener 13.11.2017 Gestion des événements
Gestion des événements 1 MouseListener L'interface MouseListener concerne les événements isoles générés a l'aide de la souris. Il s'agit d'événements de bas niveau, c'est-a-dire des actions avec la souris sur des composants qui ne sont pas équipés pour traduire ces gestes élémentaires en informations de plus haut niveau, comme c'est le cas pour les boutons, les menus, etc. Quelques méthodes de cette interface : void mousePressed(MouseEvent e) Appelée lorsqu'un bouton de la souris a été pressé, le pointeur se trouvant sur le composant qui a généré les événements. void mouseClicked(MouseEvent e) Appelée lorsque la souris a été « cliquée » (pressee puis relâchee au même endroit), le curseur se trouvant sur le composant qui a généré les événements. 13.11.2017 Gestion des événements
Gestion des événements 2 MouseMotionListener Cette interface concerne les mouvements de la souris. Lorsqu'on fait bouger la souris sans appuyer sur un de ses boutons on dit qu'on la « déplacé » (move), lorsqu'on la fait bouger tout en maintenant un bouton pressée on dit qu'on la « traîné » (drag). Cette interface comporte donc deux méthodes : void mouseMoved(MouseEvent e) Appelée lorsque la souris change de position sans qu'aucun bouton ne soit pressée. void mouseDragged(MouseEvent e) Appelée lorsque la souris change de position avec un de ses boutons pressée. Il faut être plutôt prudent en implémentant les méthodes précédentes, car elles ont à traiter des événements qui arrivent par trains. Selon les performances du système utilisé, un grand nombre d'appels de ces méthodes est généré pendant un seul déplacement de la souris. Il faut que la réponse soit courte pour ne pas ralentir l’application. MouseWeelListener définit une seule méthode mouseWheelMoved 13.11.2017 Gestion des événements
Gestion des événements 3 KeyListener Il se produit un événement clavier chaque fois qu'une touche est pressée ou relâchee. Tous les composants peuvent être sources de tels événements, il suffit qu'ils « aient le focus ». Cette interface se compose de trois méthodes : void keyPressed(KeyEvent e) Appelée lorsqu'une touche a été pressée. void keyReleased(KeyEvent e) Appelée lorsqu'une touche a été relâché. void keyTyped(KeyEvent e) Appelée lorsqu'un caractère a été saisi au clavier. L'argument de ces méthodes est un objet KeyEvent, dont les méthodes les plus intéressantes sont : char getKeyChar() Renvoie le caractère associe a l'événement clavier int getKeyCode() Dans le cas de keyPressed et keyReleased, renvoie le code de touche virtuelle correspondant a la touche pressée ou relâche. 13.11.2017 Gestion des événements
Gestion des événements 4 FocusListener Les événements qui nous intéressent ici concernent l'acquisition ou la perte du focus par un composant. A tout moment, un seul composant a le focus ; par définition, c'est a lui que sont adresses les événements du clavier. Généralement, un composant acquiert le focus lorsqu'il subit un clic de la souris ; le composant qui avait le focus a ce moment-la le perd. La pression successive de la touche tabulation fait également circuler le focus parmi les composants places sur un même conteneur Cette interface se compose de deux méthodes : void focusGained(FocusEvent e) Appelée lorsque le composant en question acquiert le focus (c'est-a-dire que les actions sur le clavier lui seront désormais adressées). void focusLost(FocusEvent e) Appelée lorsque le composant perd le focus (un autre composant l'a pris). 13.11.2017 Gestion des événements
Gestion des événements 5 ActionListener Cette interface concerne des actions (avec la souris ou le clavier) sur un composant qui les traduit en une commande de plus haut niveau, comme un choix dans une liste ou un menu, une pression sur un bouton, etc. L'interface se compose d'une seule méthode : void actionPerformed(ActionEvent e) Appelée lorsqu'une action a été faite (ce que « action » veut dire dépend du composant : presser un bouton, cocher ou décocher une case a cocher, faire un choix dans un menu, etc.). 13.11.2017 Gestion des événements
Gestion des événements 6 ItemListener Il se produit un « evenement d'item » lorsqu'un item est sélectionné ou désélectionné. Par item (ItemSelectable) nous entendons dire ici un élément d'une liste déroulante, d'une liste de choix, une case a cocher, etc. Une seule méthode dans cette interface : void itemStateChanged(ItemEvent e) Appelée lorsqu'un item a été sélectionné ou désélectionné. 13.11.2017 Gestion des événements
Gestion des événements 7 AdjustmentListener Cette interface concerne les actions faites sur des objets de type Adjustable comme les barres de défilement. Une seule méthode : void adjustmentValueChanged(AdjustmentEvent e) Appelée lorsque le curseur de la barre de défilement a été déplacé (quelle qu'en soit la raison : on a tire le curseur, on a clique sur une des flèches de la barre ou bien on a clique sur la barre en dehors du curseur). En général, a la suite d'un tel événement on interroge la barre de défilement a l'aide de la méthode getValue de la classe Scrollbar. Dans le cas ou l'on dispose de plusieurs barres de défilement on peut utiliser la méthode Object getSource() pour identifier celle qui est la source de l'événement. Ces événements ne sont pas d'un usage aussi fréquent qu'on pourrait le penser car, dans la plupart des applications, les barres de défilement des fenêtres sont gérées automatiquement par des objets ScrollPane. 13.11.2017 Gestion des événements
Gestion des événements 8 TextListener Les événements de cette interface notifient les modifications du texte en cours de saisie dans un champ ou une zone de texte. Une seule methode : void textValueChanged(TextEvent e) Appelée lorsque le texte concerné a changé. On notera que les champs de texte (TextField et TextArea) produisent également un événement action lorsque l'utilisateur presse la touche « Entrée », ce qui est souvent l'événement réellement obtenu. 13.11.2017 Gestion des événements
Gestion des événements 9 WindowListener Les événements que cette interface concerne sont les actions sur une fenêtre : ouverture et fermeture et, dans le cas d'un Frame ou d'un dialogue, les actions sur les éléments de la barre de titre. Ce qui donne les méthodes : void windowClosing(WindowEvent e) Appelée lorsque l'utilisateur essaye de fermer la fenêtre. void windowActivated(WindowEvent e) Appelée lorsque la fenêtre est rendue active. void windowDeactivated(WindowEvent e) Appelée lorsqu'une fenêtre cesse d'être la fenêtre active. void windowClosed(WindowEvent e) Appelée lorsque la fenêtre a été fermée, suite a un appel de sa méthode dispose. Ne pas confondre cet événement avec l'événement windowClosing. 13.11.2017 Gestion des événements
Gestion des événements 9 WindowListener void windowOpened(WindowEvent e) Appelée lorsqu'une fenêtre est rendue visible pour la première fois. void windowIconified(WindowEvent e) Appelée lorsqu'une fenêtre est minimisée. void windowDeiconified(WindowEvent e) Appelée lorsqu'une fenêtre qui avait été minimisée retrouve une taille normale. 13.11.2017 Gestion des événements
Gestion d’un événement Lorsqu'un événement est crée, le composant qui en est la source (Observable) a la charge de notifier ce fait a tous les objets qui ont été enregistre auprès de lui comme étant « concernés » par ce type d'événements et souhaitant donc être prévenus lorsqu'ils se produiraient. Ce mécanisme de notification des événements dans java.awt implémente le Design Pattern Observateur. Bien entendu, « notifier un événement » c'est appeler une certaine méthode, spécifique de l'événement. Les objets qui demandent a recevoir les notifications (Observateurs) des événements d'un certain type doivent donc posséder les méthodes correspondantes ; on garantit cela en imposant que ces objets soient des implémentations d'interfaces nommées XxxListener, ou Xxx caractérise le type d'événement considéré : MouseListener, WindowListener, ActionListener, etc. 13.11.2017 Gestion des événements
Gestion d’un événement En résume : pour qu'un objet puisse recevoir les notifications d'une catégorie Xxx d'événements il faut que sa classe implémente l'interface XxxListener ; cet objet peut alors être enregistre auprès d'une source d'evenements Xxx en tant qu'auditeur (listener ) des evenements Xxx. Par conséquent, si un objet est source d'événements Xxx alors il doit posséder la méthode addXxxListener grâce a laquelle d'autres objets lui sont enregistres en qualité d'auditeurs de ces événements. 13.11.2017 Gestion des événements
Gestion des événements Schéma Une source d’événement peut enregistrer 1 ou plusieurs auditeurs d’événements (dans ce cas tous les auditeurs sont notifiés). Chaque auditeur peut implémenter 1 ou plusieurs interfaces . Lorsqu’un événement se produise dans le système JVM notifie tous les auditeurs qui ont été enregistrer pour écouter à ce type d’éventement et par conséquent le traitement associé est éxécuté. 13.11.2017 Gestion des événements
Exemple de gestion des événements Source Auditeur Action Enregistrement de l’auditeur 13.11.2017 Gestion des événements
Exemple de gestion des événements Le code précèdent met en évidence les trois éléments clés dans tout processus d'exploitation d'actions de l'utilisateur : 1- les événements qu'il faut détecter et traiter ; ici, il s'agit des instances de la classe ActionEvent. Notez que le programme ne montre pas la création de ces objets, pas plus que l'appel des méthodes pour les exploiter, cela est l'affaire de méthodes (hérites de la classe Component) qui ne sont appelées que par la machine Virtuelle Java ; 2- la source de ces événements, une instance indirecte de la classe java.awt.Component. Ici, la source des événements est l'objet Button qui est la valeur de la variable b ; 3- le gestionnaire de ces événements, un auditeur dûment enregistré auprès de la source. Ici, cet auditeur est une instance, nommée a, de notre classe Auditeur. 13.11.2017 Gestion des événements
Exemple de gestion des événements On constate donc que l'expression b.addActionListener(a) joue un rôle central dans cette affaire : elle indique que le bouton b est considère ici comme une source d'événements souris et que ces événements, lorsqu'ils surviennent, doivent être notifiés a l'objet a de type Auditeur. 13.11.2017 Gestion des événements
Gestion des événements Adaptateurs 13.11.2017 Gestion des événements
Gestion des événements Adaptateurs Quand on écrit l'implémentation d'une interface XxxListener il est regrettable de devoir à écrire toutes les méthodes de l'interface alors que seul un petit nombre d'événements possibles, voire un seul, nous intéresse. Les adaptateurs sont des implémentations toutes prêtes des interfaces d'auditeurs d'événements, entièrement faites de méthodes vides. Chaque interface XxxListener possède une classe XxxAdapter correspondante. Pour écrire le traitement des événements qui nous intéressent il sut alors de définir une sous classe de l'adaptateur concerne, dans laquelle seules les méthodes pertinentes sont définies. En utilisant un adaptateur de l’interface MouseListener l’exemple précédent devient : 13.11.2017 Gestion des événements
Gestion des événements Adaptateur 13.11.2017 Gestion des événements
Gestion des événements Remarque Il est courant de disposer de plusieurs moyens d'activer la même commande. L'utilisateur peut choisir une certaine fonction au moyen d'un menu, une touche ou un bouton sur une barre d'outils. Cela est facile à réaliser dans le système de gestion des événements AWT: relier tous les événements au même auditeur. Par exemple, supposons que blueAction est un auditeur dont l'action actionPerformed méthode change la couleur du fond à la couleur bleue. Vous pouvez joindre le même auditeur d'événement à plusieurs sources: • Une barre d'outils bouton "Bleu" • Un menu intitulée "Bleu" etc... Et lorsque l’utilisateur click sur l’un de ces composant la même action sera exécutée. 13.11.2017 Gestion des événements
Gestion des événements Problème Dans l’exemple précédent on veut que l’événement click du button Ok agit sur le background du button ou bien sur un autre composant qu’on a ajouter a notre Frame ( une zone de test par exemple) ? 1- solution : utiliser une classe interne comme auditeur 2- solution : déclarer le conteneur la classe ActionEventTest comme auditeur 13.11.2017 Gestion des événements
Gestion des événements Les classes Internes Introduction Avec Java 1.0, il n'est possible de créer des classes public ou non qu'au niveau le plus haut dans un fichier .java, c'est à dire des classes externes dépendant directement d'un package. Java 1.1 (1998) introduit la possibilité de créer des classes internes qui sont déclarées à l'intérieur d'une classe, en plus des méthodes et des champs. class ClasseExterne { // Déclararation d'une classe interne Modificateur class ClasseInterne extends nomDeSuperClasse implements nomInterface // Corps de ClasseInterne : // Déclaration des champs, des méthodes, des constructeurs,... } 13.11.2017 Gestion des événements
Gestion des événements Les classes Internes De même dans un bloc, il est possible de déclarer des classes internes locales dont la portée est limitée au bloc. Dans ce cas, Modificateur ne peut prendre comme valeur que final ou abstract. Une classe interne peut déclarer elle-même d'autres classes internes. Pour chacune des classes internes déclarées est généré un fichier .class à la compilation. Pour assurer l'unicité du nom de ces fichiers, la syntaxe suivante est utilisée : La classe interne ClasseInterne déclarée à l'intérieur d'une classe externe ClasseExterne, sera stockée dans le fichier ClasseExterne$ClasseInterne.class. Si vous avez une classe interne ClasseInterne1 qui contient une autre classe interne ClasseInterne2 cette dernière sera stocké dans ClasseExterne$ClasseInterne1. ClasseInterne2.class 13.11.2017 Gestion des événements
Gestion des événements Utilisation Bien qu'il ne soit pas obligatoire de s'en servir, les classes internes apportent un plus pour l'organisation et la programmation des classes de votre programme : L'existence de certaines classes n'a de sens que dans le contexte d'une autre classe. Dans ce cas, il peut être intéressant de les déclarer comme classes internes pour montrer aux utilisateurs de ces classes dans quel contexte elles s'utilisent. Les classes externes peuvent avoir un modificateur d'accès public ou friendly. Toutes les classes non public d'un package donné sont accessibles à toutes les autres classes de ce package, ce qui n'a pas toujours l'effet désiré. Une classe interne dont le modificateur d'accès est private n'est accessible que par la classe externe dans laquelle elle est déclarée. Les classe interne peuvent accéder aux variable private de leurs classe externe. 13.11.2017 Gestion des événements
Gestion des événements Utilisation Une classe interne peut être déclaré de telle façon à devenir invisible dans le même package. Le nommage des classes est simplifié : certaines classes utilitaires de même genre peuvent avoir à être déclarées dans des contextes différents. Si ces classes sont déclarées comme classes internes, elles pourront porter le même nom sans interférer entre elles, et vous n'aurez pas à inventer des noms à rallonge pour les différencier. Comme une classe interne peut être déclarée n'importe où dans une classe, il est permis de la rapprocher de l'endroit où elle est le plus utilisée, pour améliorer la lisibilité du programme. La possibilité d'utiliser directement toutes les champs et les méthodes de la classe externe dans une classe interne non static simplifie dans de nombreux cas la programmation. Si la seule utilité d'une classe I est de satisfaire les besoins d'une autre classe E alors on peut définir I a l'intérieur de E 13.11.2017 Gestion des événements
Instanciation d’une classe interne Notez bien que vous référer à une classe interne par ClasseExterne.ClasseInterne en dehors de sa classe externe ClasseExterne obj=new ClasseExterne (); ClasseExterne.ClasseInterne obj2 = obj.new ClasseInterne (); 13.11.2017 Gestion des événements
Gestion des événements Les classes anonymes Les classes anonymes sont des classes internes crées a la volée au moment de leur instanciation. Cela est particulièrement utile lorsqu'il faut définir une sous-classe d'une classe donnée, ou une classe implémentant une interface donnée, alors qu'on n'a besoin que d'une seule instance de la nouvelle classe. Par extension des classes internes locales, vous pouvez déclarer aussi classes "anonymes". C'est un ajout à la syntaxe de l'opérateur new : Après l'instruction new Classe1 (), il est possible d'ajouter un bloc permettant de modifier le comportement de Classe1, en redéfinissant telle ou telle méthode de Classe1. Résultat : un objet d'une classe "anonyme" dérivée de Classe1 est créé, puis un transtypage implicite de cette classe vers Classe1 est effectué. 13.11.2017 Gestion des événements
Gestion des événements Syntaxe Syntaxe : SuperClasse objet = new SuperClasse (/* argument1, argument2, ...*/) { // Méthodes de SuperClasse rédéfinies // pour modifier le comportement de SuperClasse }; Dans la même logique, il est possible de créer une instance d'une classe anonyme implémentant une interface InterfaceX, grâce à l'instruction : InterfaceX objet2 = new InterfaceX () { // Implémentation de toutes les méthodes de InterfaceX }; Dans ce cas, le bloc qui suit new InterfaceX () doit implémenter toutes les méthodes de InterfaceX pour qu'il soit possible de créer une instance d'une telle classe. Comme toute classe interne, une classe anonyme peut déclarer un ensemble d’attributs et de méthodes d'instances. 13.11.2017 Gestion des événements
Gestion des événements utilisation Pour chacune des classes anonymes déclarées est généré un fichier .class à la compilation. Pour assurer l'unicité du nom de ces fichiers, le nom de chaque fichier est constitué du nom de la classe externe suivi du symbole $ et d'un identifiant numérique généré par le compilateur, comme par exemple ClasseExterne$1.class. Bien que les classes anonymes peuvent en apparence obscurcir la lisibilité d'un programme, il existe un ensemble de circonstances où il est intéressant de les utiliser : Pour créer une seule instance d'un objet d'une classe dont on veut redéfinir quelques méthodes. Implémenter localement une interface telle qu'un auditeur. Ce type d'interface est utilisé dans la gestion de l'Interface Utilisateur AWT à partir de Java 1.1 pour déclarer les méthodes qu'une classe doit implémenter pour être rappelées quand un événement survient. 13.11.2017 Gestion des événements
Exemple : classe interne 13.11.2017 Gestion des événements
Exemple : classe anonyme 13.11.2017 Gestion des événements
Gestion des événements 2- solution Vous pouvez déclarer le conteneur comme étant un auditeur qui écoutes les événement qui peuvent êtres générer par les composants de votre application, exemple : voir diapos N°4. 13.11.2017 Gestion des événements
Gestion des événements Conclusion Dans ce chapitre on a : - Définit c’est quoi un événement Vu comment gérer un événement Définit le concept d’adaptateur Identifié les Principaux types d'événements introduit des classes internes et classes anonymes. 13.11.2017 Gestion des événements