FAQ Java GUIConsultez toutes les FAQ

Nombre d'auteurs : 51, nombre de questions : 152, dernière mise à jour : 29 juin 2013 

 
OuvrirSommaireAWT et SwingLes listeners

Dans le contexte d'une interface graphique (Swing, AWT, etc), les listeners permettent au programmeur de réagir suite aux actions de l'utilisateur (clic de souris, touche du clavier enfoncée, etc).

Les « listeners » sont des interface. Ces interfaces fournissent une ou plusieurs méthodes qui peuvent donc être implémentées différemment selon les cas et les besoins, pour répondre aux événements.

Les interfaces « listener » sont présentes principalement dans le package java.awt.event, mais également dans le package javax.swing.event.

Chaque listener dispose d'une classe Event associée. Cette classe étend java.awt.event.EventObject et fournit une description de l'évènement capturé. Par exemple, la classe ActionEvent décrit les évènements capturés par un ActionListener.

Il y a plusieurs manières d'utiliser les listeners, vous trouverez ces méthodes dans les Q/Rs suivantes.

Mis à jour le 15 novembre 2008  par Janitrix

Voici la présentation et quelques explications sur la première possibilité concernant l'utilisation des listeners.

1ère possibilité : implémentation de l'interface dans la classe principale.

 
Sélectionnez
import java.awt.event.ActionListener; 
 
// Étape 1 : déclaration de la classe 
public class MaClasse implements ActionListener { 
	// Étape 3 : Création de deux boutons
	JButton monBouton = new JButton("Mon Bouton"); 
	JButton monBouton2 = new JButton("Mon Bouton2"); 
 
	public MaClasse() { 
		// Étape 4 : On ajoute « l'écouteur » sur le bouton « monBouton ». 
		monBouton.addActionListener(this); 
		// Puis sur monBouton2
		monBouton2.addActionListener(this);
	} 
 
	/* Étape 2 :Cette méthode est déclarée dans l'interface ActionListener. Il nous faut l'implémenter. */ 
	public void actionPerformed(ActionEvent e) { 
                // Étape 2bis
		if(e.getSource() == monBouton) {
			// Bouton 1 a été cliqué
		}else {
			// Bouton 2 a été cliqué
		}
	} 
}

Tout d'abord, à l'étape 1, nous déclarons une classe « MaClasse » qui implémente l'interface ActionListener (nous l'étudierons plus en détail dans une autre Q/R). Puisque nous implémentons l'interface, nous devons également implémenter toutes les méthodes définies dans l'interface.

Le cas de l'interface ActionListener est simple puisqu'elle ne contient qu'une méthode.

Méthode que nous implémentons à l'étape 2 justement.

Nous créons un bouton SWING à l'étape 3.

À l'étape 4, nous ajoutons un « listener » sur les boutons précédemment créés. La méthode addActionListener est définie dans la classe AbstractButton, classe parente de JButton. Cette méthode attend un paramètre de type ActionListener.

La classe MaClasse implémente cette interface, elle peut être justement considérée comme du type ActionListener. Nous pouvons donc fournir l'opérateur 'this' en paramètre, qui représente l'instance en cours de la classe MaClasse.

Concrètement, qu'avons nous fait ? Nous avons demandé aux boutons monBouton et monBouton2 qu'ils nous préviennent lorsqu'un utilisateur les actionne (c'est le rôle du « listener » ActionListener en particulier). Et comment ? En utilisant la méthode actionPerformed, définie dans l'interface ActionListener et surchargée dans la classe MaClasse.

Nous avons deux boutons, mais une seule méthode actionPerformed. Nous devons donc différencier (étape 2bis) la source de l'évenement, monBouton ou monBouton2.

La boucle est bouclée.

Créé le 15 novembre 2008  par Janitrix

2ème méthode : Utilisation des classes anonymes

Une deuxième possibilité est d'utiliser les classes anonymes. Voici quelques explications, toujours avec un code pour l'exemple.

 
Sélectionnez

// Étape 1 : déclaration de la classe
public class MaClasse { 
	// Étape 2 : création de deux boutons. 
	JButton monBouton = new JButton("Mon Bouton"); 
	JButton monBouton2 = new JButton("Mon Bouton 2"); 
 
	/* Étape 3 : création de la  classe anonyme */ 
	monBouton.addActionListener(new ActionListener() { 
		public void actionPerformed(ActionEvent e) { 
			// Cette méthode ne sera appelée que pour les évènements sur le bouton monBouton. 
		} 
	}); 
 
	/* On refait la même chose pour le deuxième bouton */ 
	monBouton2.addActionListener(new ActionListener() { 
		public void actionPerformed(ActionEvent e) { 
			// Cette méthode ne sera appelée que pour les évènements sur le bouton monBouton2. 
		} 
	}); 
} 

Dès le début nous pouvons remarquer quelques différences avec la première méthode d'utilisation traitée précédemment.

Tout d'abord notre classe MaClasse n'implémente pas l'interface ActionListener. Aucune instance de la classe MaClasse ne pourra donc être utilisée dans la méthode addActionListener.

Nous créons deux boutons à l'étape 2. L'étape 3 est la plus intéressante. Nous définissons une instance de l'interface ActionListener dans une classe anonyme, sans garder de référence vers cette classe anonyme. Dans ce cas, nous devons le faire deux fois, une fois pour chaque bouton (il faut une classe anonyme pour chaque composant déclenchant un évènement).

Un avantage de cette méthode est un code plus léger au niveau de l'implémentation des évènements. En effet, nous n'avons pas à dissocier les composants « source » (les composants écoutés par le listener), comme nous le faisons dans la première possibilité.

En contrepartie, nous devons créer une classe anonyme à chaque fois. Une autre possibilité qui est une simple variante de celle présentée ici est la suivante :

 
Sélectionnez

// Étape 1 : déclaration de la classe
public class MaClasse { 
	// Étape 2 : création de deux boutons. 
	JButton monBouton = new JButton("Mon Bouton..."); 
	JButton monBouton2 = new JButton("Mon Bouton 2..."); 
 
	/* Étape 3 : création de la  classe anonyme */ 
	ActionListener listener = new ActionListener() { 
		public void actionPerformed(ActionEvent e) { 
			if(e.getSource() == monBouton) {
				// Bouton 1 a été cliqué
			}else {
				// Bouton 2 a été cliqué
			}
		} 
	};
 
	monBouton.addActionListener(listener); 
	monBouton2.addActionListener(listener); 
}

Ce code est fortement similaire au précédent et mérite donc peu d'explication. La seule subtilité est que nous « sauvegardons » l'instance de la classe anonyme dans une variable, et que nous pouvons donc la réutiliser autant de fois que nécessaire. Cependant, cette façon de faire nous oblige à différencier les composants « source » pour implémenter un comportement différent selon la source.

Mis à jour le 6 juin 2009  par Janitrix

3eme méthode : création d'une classe dédiée.

 
Sélectionnez

// Fichier : MonListener.java
public class MonListener implements ActionListener { 
	public void actionPerformed(ActionEvent e) { 
	} 
} 

Et dans votre classe principale :

 
Sélectionnez
monButton.addActionListener(new MonListener()); 

Cette possibilité est très simple, il vous suffit d'implémenter le comportement voulu dans la classe qui implémente le listener, puis, vous créez une instance de cette classe que vous passez en paramètre de la méthode addXXXListener située dans votre classe où sont déclarés les composants (boutons, listes, etc).

Mis à jour le 6 juin 2009  par Janitrix

ActionListener est, comme son nom l'indique, un listener utilisé pour réagir aux actions utilisateurs. Celles-ci sont multiples, la principale étant l'activation d'un bouton (par un clic ou par appui de la touche Entrée lorsque le bouton est sélectionné).

Une seule méthode est déclarée dans cette interface : public void actionPerformed(java.awt.event.ActionEvent e).

La classe ActionEvent étend la classe java.util.EventObject, et hérite donc de ses méthodes. Parmi elles, getSource() est particulièrement intéressante. Elle renvoie l'objet concerné par l'événement (par exemple le bouton qui a été cliqué).

Cela nous permettra de différencier les composants sources dans l'implémentation de la méthode actionPerformed.

La classe ActionEvent fournit quant à elle quelques méthodes spécifiques aux évènements d'action. Les plus utilisées sont getWhen() et getActionCommand().

getWhen() récupère le timestamp Unix marquant le déclenchement de l'évènement, tandis que getActionCommand() retourne le nom de la commande associée à l'évènement (par exemple, le texte du bouton à l'origine de l'action).

Voici une simple implémentation d'un ActionListener, utilisant la première méthode d'implémentation proposée :

 
Sélectionnez

[...]
import java.awt.event.*;
 
// Étape 1 : déclaration de la classe 
public class MaClasse implements ActionListener {
	// Étape 2 : créations des boutons
	JButton monBouton = new JButton("Un bouton vivant");
	JButton monBouton2 = new JButton("Un bouton vivant2");
 
	public MaClasse() {
		// Étape 3 : on ajoute le listener aux boutons
		monBouton.addActionListener(this);
		monBouton.addActionListener(this);
	}
 
	// Étape 4 : l'implémentation de l'ActionListener
	public void actionPerformed(ActionEvent e) {
		System.out.println("Un bouton a été cliqué, timestamp : " + e.getWhen());
 
		// Étape 5 : différenciation de la source d'évènement
		if(e.getSource() == monBouton || e.getActionCommand() == monBouton.getText()) {
			System.out.println("C'est le bouton 1 !");
		}else if(e.getSource() == monBouton2 || e.getActionCommand() == monBouton2.getText()) {
			System.out.println("C'est le bouton 2 !");
		}
 
	}
}

Rien de nouveau aux étapes 1, 2, 3, et 4. Vous aurez compris que lorsque l'un des deux boutons est appuyé, la méthode actionPerformed est invoquée.

Cependant, nous avons deux boutons, et un clic sur chacun d'eux invoquera la même implémentation de l'ActionListener. Nous devons donc différencier le bouton source de l'action. Cela peut se réaliser de deux façons : soit on compare le libellé du bouton avec celui de l'action capturée, soit on compare le bouton et l'objet source de l'évènement.

Les deux méthodes sont présentées à l'étape 5. Notez que mettre ces deux tests (comparaison de libellés et comparaison de sources) dans une même condition est superflu, un seul des deux tests est nécessaire pour savoir quel bouton a été actionné.

Mis à jour le 15 novembre 2008  par Janitrix

Le KeyListener est utilisé pour réagir aux évènements du clavier, et est donc utilisable sur des composants permettant la saisi de texte (JTextField, JTextArea, etc).

Trois méthodes sont déclarées dans l'interface du KeyListener : keyTyped(KeyEvent e), keyPressed(KeyEvent e) et keyReleased(KeyEvent e). Elle permettent respectivement de réagir lorsqu'une touche a été : tapé (pressé puis relâché), pressé, relâché.

La classe KeyEvent étend java.util.EventObject et dispose donc des méthodes déclarées dans cette classe (notamment getSource() ), mais fournit également une dizaine d'autres méthodes spécifiques aux évènements relatifs au clavier. Parmi elles : getKeyChar() retourne le caractère associé à la touche appuyée, getKeyCode() récupère le code de la touche pressée, isActionKey() retourne true si la touche appuyée est une touche d'action (CAPS LOCK, Verr Num, etc), et getKeyText(int keyCode) retourne le texte associée à la touche (par ex. F1, A, etc).

La dernière méthode, getKeyText, est statique, et ne s'utilise donc pas avec l'instance de KeyEvent fournie.

Les codes retournés par la méthode getKeyCode() sont utiles pour déterminer la touche pressée.
Tous les codes et leur correspondance sont disponible ici : http://java.sun.com/javase/6/docs/ap.../KeyEvent.html

Voici une simple implémentation d'un KeyListener, utilisant la première méthode d'implémentation proposée :

 
Sélectionnez

import java.awt.event.*;
 
// Étape 1 : on crée la classe et on implémente KeyListener.
public class MaClasse implements KeyListener {
 
	// Étape 2 : on crée un composant JTextField
	private JTextField textField = new JTextField();
 
	public MaClasse() {
		// Étape 3 :  on ajoute le listener au composant
		textField.addKeyListener(this);
	}
 
	// Étape 4 : on implémente la méthode keyTyped définie dans l'interface KeyListener
	public void keyTyped(KeyEvent e) {
		/* Cette méthode est appelée quand l'utilisateur appuie sur une touche Unicode (donc les caractères) et ne prend pas en compte les touches comme F1, Echap, ALT, etc. */
		System.out.println(e.getKeyChar());
	}
 
// Étape 5: on implémente la méthode keyPressed définie dans l'interface KeyListener
public void keyPressed(KeyEvent e) {
	/* Cette méthode est appelée quand l'utilisateur appuie sur une touche.
	Il est conseillé de ne pas utiliser getKeyChar() mais getKeyCode(), car les touches spéciales comme F1 ou Echap ne disposent pas d'un équivalent en Unicode, et donc ne peuvent être représentées en char. */
        System.out.println(KeyEvent.getKeyText( e.getKeyCode() );
	if(e.getKeyCode() == KeyEvent.VK_ESCAPE) {
		System.out.println("L'utilisateur a appuyé sur Echap");
	}
}
 
// Étape 6 : on implémente la méthode keyReleased définie dans l'interface KeyListener
public void keyReleased(KeyEvent e) {
	// Le fonctionnement est le même que pour keyPressed, sauf que cette méthode est appelée quand la touche est relâchée.
}
 
}

Le code est assez explicite, et les commentaires précises quelques points obscures. Rien de nouveaux dans ce code, si ce n'est la comparaison entre le code de la touche appuyé et le code de la touche Echap.

Enfin, sachez que si vous trouvez trop lourd de devoir implémenter les 3 méthodes alors qu'une seule vous suffit, il existe la classe abstraite java.awt.event.KeyAdapter.

Vous pouvez soit créer une classe qui étendra KeyAdapter, soit faire une classe anonyme.

Exemple :

 
Sélectionnez

monTextField.addKeyListener(new KeyAdapter() {
	public void keyTyped(KeyEvent e) {
	}
});
Mis à jour le 15 novembre 2008  par Janitrix

Lien : La documentation officielle sur le KeyListener
Lien : La documentation officielle sur le KeyEvent

Le MouseListener est utilisé pour les événements relatifs à la souris (clics, déplacements).

5 méthodes sont déclarées dans l'interface MouseListener : mouseClicked(MouseEvent e) prévient des clics (la souris a été pressée puis relâchée), mousePressed(MouseEvent e) pour les pressions sur la souris (donc on enfonce le bouton sans le relâcher), mouseReleased(MouseEvent e) prévient du relâchement d'un bouton de la souris, mouseEntered(MouseEvent e) indique que la souris est entrée dans l'espace d'un composant, mouseExited(MouseEvent e) indique que la souris est sortie de l'espace d'un composant.

La classe MouseEvent étend java.util.EventObject et dispose donc des méthodes déclarées dans cette classe (notamment getSource() ), mais fournit également 12 autres méthodes spécifiques aux événements relatifs à la souris, notamment getButton() retourne le bouton qui a été cliqué, getClickCount() retourne le nombre de clics (utile pour gérer le double clic), getLocationOnScreen() retourne un objet Point représentant la position de la souris à l'écran, et enfin
isPopupTrigger() précise si le bouton cliqué est celui habituellement utilisé pour afficher la liste déroulante (bouton droit sur le bureau Windows par exemple).

Voici un exemple d'implémentation d'un MouseListener :

 
Sélectionnez
<code langage="java">public class MaClasse implements MouseListener {
 
	public void mousePressed(MouseEvent e) {
		// Cette méthode est appelée quand l'utilisateur appuie le bouton sur le composant écouté
	}
 
	public void mouseReleased(MouseEvent e) {
		// Cette méthode est appelée quand l'utilisateur relâche le bouton sur le composant écouté
	}
 
	public void mouseClicked(MouseEvent e) {
		// Cette méthode est appelée quand l'utilisateur a cliqué (appuyé puis relâché) sur le 	composant écouté
		if(e.getClickCount() == 2) {
			System.out.println("Il y a eu un double clic");
		}
 
		Point p = e.getLocationOnScreen();
 
		System.out.println("La souris est aux coordonnées : x=" + p.getX() + ";y=" + p.getY() + " de l'écran.");
	}
 
	public void mouseEntered(MouseEvent e) {
		// Cette méthode est appelée quand la souris entre dans la zone du composant écouté
		System.out.println("La souris vient d'entrer...");
	}
 
	public void mouseExited(MouseEvent e) {
		// Cette méthode est appelée quand la souris sort de la zone du composant écouté
		System.out.println("La souris vient de sortir... rattrapez  :)");
	}
}

Il est fort probable que seules quelques unes de ces méthodes vous intéressent, il vous semblera donc lourd d'implémenter chacune des méthodes..

Il existe donc une classe abstraite MouseAdapter qui vous permet d'implémenter seulement les méthodes qui vous intéressent.

Exemple :

 
Sélectionnez

monPanel.addMouseListener(new MouseAdapter() {
	public void mouseClicked(MouseEvent e) {
	}
}
Mis à jour le 15 novembre 2008  par Janitrix

Le WindowListener est utilisé pour les événements relatifs aux fenêtres (activation, fermeture, ouverture, etc).

Cette interface déclare 7 méthodes : windowActivated(WindowEvent e) indique que la fenêtre a été activé, windowDeactivated(WindowEvent e) indique que la fenêtre n'est plus la fenêtre active,windowClosed(WindowEvent e) indique que la fenêtre a été fermé, windowClosing(WindowEvent e) indique que l'utilisateur a demandé la fermeture de la fenêtre, windowOpened(WindowEvent e) est appelé la première fois que la fenêtre est rendue visible, windowIconified(WindowEvent e) indique que la fenêtre a été réduite dans la barre de tâche, windowDeiconified(WindowEvent e) indique que la fenêtre a été restauré depuis la barre de tâche.

La classe WindowEvent étend java.util.EventObject et dispose donc des méthodes déclarées dans cette classe (notamment getSource() ), mais fournit également 5 autres méthodes spécifiques aux événements relatifs aux fenêtres, notamment getNewState() et getOldState() qui fournissent respectivement le nouvel état et l'ancien état de la fenêtre, mais aussi getWindow(), qui retourne la fenêtre source de l'événement.

Afin d'ajouter un WindowListener sur une fenêtre, vous disposez de la méthode addWindowListener(WindowListener) de la classe Window (étendue par la classe JFrame notamment).

Voici un exemple d'implémentation d'un WindowListener :

 
Sélectionnez
public class MaClasse implements WindowListener {
 
	// [...]
 
        public MaClass() {
             maFenetre.addWindowListener(this);
        }
 
	public void windowOpened(WindowEvent e) {
		System.out.println("On vient de m'ouvrir !");
	}
 
	public void windowClosed(WindowEvent e) {
		System.out.println("On m'a fermé !")
	}
	public void windowClosing(WindowEvent e) {
		System.out.println("On veut me fermer !");
	}
 
	public void windowIconified(WindowEvent e) {
		System.out.println("Je suis réduite à une icône !");
	}
 
	public void windowDeiconified(WindowEvent e) {
		System.out.println("Je suis restaurée !");
	}
 
	public void windowActivated(WindowEvent e) {
		System.out.println("Je suis activée");
	}
 
	public void windowDeactivated(WindowEvent e) {
		System.out.println("Je suis désactivée");
	}
 
} 

Les méthodes sont nombreuses mais bien spécifiques. Il existe encore une fois une classe Adapter qui vous permet de n'implémenter que les méthodes qui vous intéressent : WindowAdapter.

Mis à jour le 15 novembre 2008  par Janitrix

Le FocusListener est utilisé pour les événements relatifs au focus clavier.

Cette interface déclare 2 méthodes : focusGained(FocusEvent e) indique que le composant a gagné le focus clavier tandis que focusLost(FocusEvent e) indique que le composant a perdu le focus clavier.

La classe FocusEvent étend java.util.EventObject et dispose donc des méthodes déclarées dans cette classe (notamment getSource() ), mais fournit également 3 autres méthodes spécifiques aux événements relatifs aux fenêtres, notamment isTemporary() qui indique si le composant n'a le focus que temporairement, et getOppositeComponent() qui retourne l'autre composant impliqué dans le changement de focus.

Afin d'ajouter un FocusListener, vous disposez de la méthode addFocusListener(FocusListener) de la classe Component.

Voici un exemple d'implémentation d'un FocusListener :

 
Sélectionnez

public class MaClasse implements FocusListener {
     public MaClasse() {
         monComposant.addFocusListener(this);
     }
 
     public void focusGained(FocusEvent e) {
          System.out.println("On a gagné le focus");
     }
 
     public void focusLost(FocusEvent e) {
         System.out.println("On a perdu le focus");
     }
}
Mis à jour le 15 novembre 2008  par Janitrix

Le ItemListener est utilisé pour les évènements relatifs aux éléments (liste, checkbox, etc).

Cette interface déclare une seule méthode : itemStateChanged(ItemEvent e) qui indique que l'élément a changé d'état.

La classe ItemEvent étend java.util.EventObject et dispose donc des méthodes déclarées dans cette classe (notamment getSource() ), mais fournit également 4 autres méthodes spécifiques aux événements relatifs aux fenêtres, notamment getItem() qui retourne l'élément affecté par l'évènement, getStateChange() retourne le nouvel état de l'élément (sélectionné ou désélectionné), et getItemSelectable() qui retourne le composant originaire de l'évènement.

Afin d'ajouter un ItemListener sur les composants qui le permettent (les boutons, JcomboxBox, les listes, etc), vous disposez de la méthode addItemListener(ItemListener).

Voici un exemple d'implémentation d'un ItemListener :

 
Sélectionnez

public class MaFrame extends JFrame implements ItemListener {
	private JComboBox choix;
 
	// [...]
 
        public MaFrame() {
            choix = new JComboBox();
            choix.addItemListener(this);
        }
 
	public void itemStateChanged(ItemEvent e) {
		if(e.getStateChange() == ItemEvent.SELECTED) {
			System.out.println("Un nouveau choix est sélectionné*: " + e.getItem().toString());
		}else if(e.getStateChange() == ItemEvent.DESELECTED) {
			System.out.println("*Un choix est désélectionné*: " + e.getItem().toString());
		}
	}
}

Nous effectuons un test afin de savoir l'état de l'élément affecté par l'évènement. En effet, deux états sont possibles : ItemEvent.ITEM_SELECTED et ItemEvent.DESELECTED. Il faut bien comprendre que la méthode itemStateChanged est invoquée deux fois : une fois pour l'élément qui vient d'être désélectionné et une fois pour celui qui vient d'être sélectionné (ceci est vrai dans le cas d'une JComboBox par exemple). Il est donc important de faire la différence, sous peine de voir son code exécuté deux fois.

Mis à jour le 15 novembre 2008  par Janitrix
Les codes sources présentés sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Pour le reste, ce document constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Ce document issu de http://www.developpez.com est soumis à deux licences, en fonction des contributeurs : - Les contributions de Clément Cunin et Johann Heymes sont soumises aux termes de la la licence GNU FDL traduite en français ici. Permission vous est donnée de distribuer, modifier des copies des contributions de Clément Cunin et Johann Heymes tant que cette note apparaît clairement : "Ce document issu de http://www.developpez.com est soumis à la licence GNU FDL traduite en français ici. Permission vous est donnée de distribuer, modifier des copies de cette page tant que cette note apparaît clairement". - Pour ce qui est des autres contributions : Copyright © 2004 - 2009 Developpez LLC : Tous droits réservés Developpez LLC. Aucune reproduction ne peut en être faite sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD.