IdentifiantMot de passe
Loading...
Mot de passe oubli� ?Je m'inscris ! (gratuit)
logo

FAQ Langage JavaConsultez toutes les FAQ

Nombre d'auteurs : 42, nombre de questions : 297, derni�re mise � jour : 19 septembre 2017  Ajouter une question

 

Cette FAQ a �t� r�alis�e � partir des questions fr�quemment pos�es sur le forum Java de http://java.developpez.com ainsi que l'exp�rience personnelle des auteurs.

Nous tenons � souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes. Les auteurs font leur maximum, mais l'erreur est humaine. Cette FAQ ne pr�tend pas non plus �tre compl�te. Si vous trouvez une erreur, ou que vous souhaitez nous aider en devenant r�dacteur, lisez ceci.

Sur ce, nous vous souhaitons une bonne lecture.

SommaireBases du langage�v�nements (6)
pr�c�dent sommaire suivant
 

Les listeners (�couteurs) et events (�v�nements) sont une mise en �uvre du patron de conception observateur�: ils permettent d�envoyer des notifications, par exemple la modification d'une valeur, depuis un module ou une sous-partie de l'application vers un autre module de l'application. Le module receveur peut alors r�agir en cons�quence en fonction des informations qui lui ont �t� transmises. Le listener ou �couteur repr�sente la partie qui re�oit la notification�; on parle aussi d'observer ou observateur. L�event ou �v�nement est l'information qui est transmise par la notification.

Le package java.util dispose de plusieurs classes et interfaces qui permettent de d�finir ces entit�s.

Une premi�re impl�mentation concr�te a �t� fournie dans le JDK�1.0, mais elle s�av�re peu utilis�e�:

  • java.util.Observable - depuis le JDK�1.0, l�impl�mentation concr�te d'un objet qui peut �tre observ�;
  • java.util.Observer - depuis le JDK1.0, l�impl�mentation concr�te d'un objet qui peut en observer un autre.


Une seconde impl�mentation plus facile � �tendre et � d�river a �t� d�ploy�e dans le JDK�1.1 �:

  • java.util.EventObject - � partir du JDK�1.1, cette classe est la classe m�re de presque tous les objets event�;
  • java.util.EventListener - � partir du JDK�1.1, cette interface est l'interface m�re de presque tous les objets listener.


Cette seconde API, � laquelle nous allons nous int�resser, est tr�s pr�sente dans tout le JDK. Elle est principalement utilis�e dans les interfaces graphiques AWT, Swing et JavaFX, mais se trouve �tre �galement pr�sente dans des portions du JDK ayant peu ou pas de rapport avec les interfaces graphiques�: ImageIO, les beans ou encore JDBC. L'API XML DOM utilise un concept de gestion d��v�nements identique, mais qui n�h�rite pas directement des interfaces et classes d�finies dans java.util.

Mis � jour le 13 octobre 2015 bouye

Pour d�finir votre propre event, c'est assez simple�: vous devez tout simplement cr�er une classe qui h�rite de java.util.EventObject et dans laquelle vous allez stocker toute information que vous jugez utile de faire remonter dans votre notification. L'objet �v�nement contient �galement une r�f�rence � la source de l��v�nement, car un m�me observateur peut s'enregistrer aupr�s de plusieurs sources et donc il a besoin de connaitre laquelle lui fait parvenir une notification.

Par convention, le nom de l��v�nement est constitu� du nom de la valeur, variable ou entit� observ�e suivi du mot Event�:

  • MouseEvent - colporte les d�tails des �v�nements relatifs � la souris�;
  • KeyEvent - colporte les d�tails des �v�nements relatifs aux touches du clavier�;
  • PropertyChangeEvent - colporte les d�tails des �v�nements relatifs aux modifications de valeur des propri�t�s�;
  • etc.


Par exemple, pour un capteur de temp�rature�:

Code Java : S�lectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public final class TemperatureEvent extends EventObject {      
     private final double oldTemperature; 
     private final double newTemperature; 
  
    /** 
     * Cr�e une nouvelle instance. 
     * @param source La source de l��v�nement. 
     * @param oldTemperature L'ancienne temp�rature. 
     * @param newTemperature La nouvelle temp�rature. 
     */ 
    public void TemperatureEvent(Object source, double oldTemperature, double newTemperature) { 
        super(source); 
        this.oldTemperature = oldTemperature; 
        this.newTemperature = newTemperature; 
    } 
  
    /** 
     * Retourne la temp�rature avant modification. 
     * @return Une temp�rature en degr�s Kelvin. 
     */ 
    public double getOldTemperature() { 
        return oldTemperature; 
    } 
  
    /** 
     * Retourne la temp�rature apr�s modification. 
     * @return Une temp�rature en degr�s Kelvin. 
     */ 
    public double getNewTemperature() { 
        return newTemperature; 
    } 
}

Mis � jour le 13 octobre 2015 bouye

Pour d�finir votre propre listener, c'est assez simple : vous devez tout simplement cr�er une interface qui h�rite de java.util.EventListener et dans laquelle sont d�finies une ou plusieurs m�thodes qui permettent de renvoyer des notifications.

Par convention, le nom de l'observateur est constitu� du nom de la valeur, variable ou entit� observ�e suivi du mot Listener :

  • MouseListener - observateur des �v�nements relatifs � la souris ;
  • KeyListener - observateur des �v�nements relatifs aux touches du clavier ;
  • PropertyChangeListener - observateur des �v�nements relatifs aux modifications de valeur des propri�t�s ;
  • etc.


Par convention, les m�thodes d�finies dans le listener prennent en param�tre un objet customis� qui h�rite dejava.util.EventObject et qui contient des informations suppl�mentaires en rapport avec la notification. L'objet �metteur de la notification n��tant g�n�ralement pas int�ress� par un retour de votre observateur, ces m�thodes ont g�n�ralement le type de retour void. Le nom des m�thodes reprend en g�n�ral le nom de la valeur ou variable ou entit� observ�e suivi d'un mot ou d'un adjectif indiquant le type de notification :

  • mousePressed() - l'utilisateur appuie sur un bouton de la souris ;
  • keyReleased() - l'utilisateur a rel�ch� son doigt d'une des touches du clavier ;
  • propertyChange() - la valeur d'une propri�t� a �t� modifi�e ;
  • etc.


Par exemple, pour un capteur de temp�rature :

Code Java : S�lectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
public interface TemperatureListener extends EventListener { 
    /** 
     * Invoqu�e quand la temp�rature monte. 
     * @param event Les d�tails de l��v�nement. 
     */ 
    public void temperatureRaised(TemperatureEvent event); 
  
    /** 
     * Invoqu�e quand la temp�rature baisse. 
     * @param event Les d�tails de l��v�nement. 
     */ 
    public void temperatureDropped(TemperatureEvent event); 
}

Lorsque votre listener contient plusieurs m�thodes, on fournit g�n�ralement une classe abstraite nomm�e Adapter qui contient des impl�mentations vides de ces m�thodes. Cela permet par la suite de cr�er des nouvelles instances du listener en h�ritant de l'adapter et donc sans devoir impl�menter les m�thodes qui ne nous int�ressent pas.

Code Java : S�lectionner tout
1
2
3
4
5
6
7
8
9
public class TemperatureAdapter implements TemperatureListener { 
    @Override 
    public void temperatureRaised(TemperatureEvent event) { 
    } 
  
    @Override 
    public void temperatureDropped(TemperatureEvent event) { 
    } 
}

Mis � jour le 13 octobre 2015 bouye

Maintenant que vous avez votre interface listener et votre objet event, il vous faut un objet observable, c'est-�-dire qui sera la source des notifications que vont recevoir vos observateurs. Nous allons commencer par ajouter des m�thodes permettant d'enregistrer et de d�senregistrer des �couteurs sur votre objet.

Par convention, ces m�thodes sont nomm�es add (pour ��ajout��) ou remove (pour ��retrait��) suivi du nom de la valeur, variable ou entit� observ�e suivi du mot Listener et elles prennent en argument un listener du type appropri�: addXXXListener(XXXListener) et removeXXXListener(XXXListener).

Par exemple, pour un capteur de temp�rature�:

  • addTemperatureListener(TemperatureListener listener) - pour l'ajout�;
  • removeTemperatureListener(TemperatureListener listener) - pour le retrait.


Les choses sont un peu diff�rentes en JavaFX o� on utilise des m�thodes simplement nomm�es addListener() et removeListener() en distinguant le type d��couteur utilis� gr�ce au type du param�tre de chaque m�thode.

Nous allons devoir maintenant impl�menter le stockage des �couteurs dans l'objet. Si votre objet est un bean, vous pouvez utiliser la classe java.beans.PropertyChangeSupport. Si votre objet est un composant Swing, vous pouvez utiliser la classe javax.swing.EventListenerList. Et si votre objet est un contr�le JavaFX, vous utiliserez les classes propri�t�s pr�sentes dans cette API. Mais nous allons partir du principe que vous n'utilisez aucune de ces API.

On utilisera donc un tableau ou une liste pour stocker tous les �couteurs enregistr�s sur notre objet observable. Bien qu'il soit possible de stocker un conteneur par type d��couteur, en g�n�ral on utilise un seul conteneur pour tous les types de listeners qui peuvent �tre enregistr�s sur l'objet. De plus, pour conserver de bonnes performances et pour �viter de lancer des instance of � tout va lors du parcours de la liste, on stockera aussi le type de l'�couteur enregistr�. Notre liste aura donc toujours un nombre pair d��l�ments et sera constitu�e comme suit�: [type �couteur A, �couteur A, type �couteur B, �couteur B, type �couteur C, �couteur C, [...] , type �couteur N, �couteur N].

Dans notre capteur de temp�ratures, nous avons donc d�sormais�:

Code Java : S�lectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public class TemperatureSensor { 
    // Conteneur pour tous les observateurs sur cet objet. 
    private final List listenerList = new LinkedList(); 
  
    /** 
     * Enregistre un �couteur de temp�rature. 
     * @param listener L��couteur. 
     */ 
    public void addTemperatureListener(TemperatureListener listener) { 
        if (listener == null) { 
            return; 
        } 
        // On ajoute le listener et son type. 
        // Cela permet de stocker plusieurs types de listeners dans le m�me conteneur. 
        listenerList.add(TemperatureListener.class); 
        listenerList.add(listener); 
    } 
  
    /** 
     * D�senregistre un �couteur de temp�rature. 
     * @param listener L��couteur. 
     */ 
    public void removeTemperatureListener(TemperatureListener listener) { 
        if (listener == null) { 
            return; 
        } 
        removeListener(TemperatureListener.class, listener); 
    } 
  
    /** 
     * M�thode g�n�rique pour d�senregistrer un �couteur. 
     * @param listenerClass Le type de l��couteur. 
     * @param listener L��couteur. 
     */ 
    private void removeListener(Class listenerClass, Object listener) { 
        int listSize = listenerList.size();         
        for (index = 0; index < listSize�; index += 2) { 
            // Comme un listener peut impl�menter plusieurs interfaces et s'enregistrer plusieurs fois, 
            // on v�rifie qu'on enl�ve le premier rencontr� qui porte le bon type. 
            if (listenerList,get(index) == listenerClass && listenerList.get(index + 1) == listener) { 
                listenerList.remove(index + 1); 
                listenerList.remove(index); 
                break; 
            } 
        } 
    } 
}

Nous pouvons d�sormais enregistrer des listeners sur notre senseur de temp�rature, par exemple en faisant�:

Code Java : S�lectionner tout
1
2
3
4
5
6
7
TemperatureSensor senseur = [...] 
senseur.addTemperatureListener(new TemperatureAdapter() { 
    @Override 
    public void temperatureRaised(TemperatureEvent event) { 
        System.out.printf("La temp�rature est mont�e de %.2fK � %.2fK.%n", event.getOldTemperature(), event.getNewTemperature()); 
    } 
});

Mis � jour le 14 octobre 2015 bouye

Nous pouvons d�sormais enregistrer des �couteurs dans notre objet observable, mais il nous manque encore le code qui permet d'envoyer des notifications aux observateurs. Ces notifications sont g�n�ralement lanc�es dans les m�thodes setter ou encore aux endroits o� le code est amen� � modifier les valeurs des membres ou propri�t�s de l'objet.

Le principe est de cr�er des m�thodes qui vont parcourir la liste des observateurs � rebours. En effet, on part du principe que cette liste se comporte comme une pile LIFO (Last In First Out - dernier entr�, premier sorti) et donc que les �couteurs les plus r�cemment ajout�s dans la liste seront ceux qui recevront la notification en premier.

Par convention, ces m�thodes sont en acc�s private ou protected et sont nomm�es fire (pour ��tirer�� ou ��lancer��) suivi du nom de la valeur, variable ou entit� observable suivi du mot Event ou du type d��v�nement lanc�.

Par exemple, ici pour notre senseur de temp�rature�: fireTemperatureEvent() ou fireTemperatureRaised() suivant ce que l'on pr�f�re.

Code Java : S�lectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
protected void fireTemperatureRaised(double oldTemperature, double newTemperature) { 
    TemperatureEvent event = null; 
    int listSize = listenerList.size(); 
    // On parcourt la liste � rebours. 
    for (int index = listSize - 2; index >= 0; index -= 2) { 
        // Seules les instances de TemperatureListener nous int�ressent. 
        if (listenerList.get(index) == TemperatureListener.class) { 
            // On cr�e l'objet event de mani�re "lazy" (paresseuse), uniquement quand on en a vraiment besoin. 
            if (event == null) { 
                event = new TemperatureEvent(this, oldTemperature, newTemperature); 
            } 
            TemperatureListener  listener = (TemperatureListener)listenerList.get(index + 1); 
            // On invoque la notification appropri�e sur le listener. 
            listener.temperatureRaised(event); 
        } 
    } 
}

Ce qui permet de mettre dans le code charg� de relever la temp�rature sur le capteur physique�:

Code Java : S�lectionner tout
1
2
3
4
5
6
7
8
// Sauvegarde de l'ancienne temp�rature. 
double oldTemperature = temperature; 
// Relever la temp�rature sur le capteur physique. 
temperature = [...] 
// Lancer une notification d��l�vation de temp�rature si besoin. 
if (temperature > oldTemperature) { 
    fireTemperatureRaised(oldTemperature, temperature); 
}

Avertissement�: la notification aux observateurs se d�roule de mani�re lin�aire et s�quentielle (les uns apr�s les autres) dans le thread en train d�ex�cuter le code de l'objet observable. Il y a donc quelques points importants qu'il faut bien prendre en compte�:
  • si un listener ex�cute un code de longue dur�e en r�ponse � cette notification, il mettra en attente non seulement les notifications destin�es aux autres observateurs, mais aussi le code dans l'objet observable. Les t�ches de longue dur�e devront donc �tre ex�cut�es, c�t� listener, dans des threads s�par�s�;
  • toute erreur ou exception, non trait�e par le code du listener remontera jusqu�� l'objet observable et bloquera les notifications aux autres observateurs, mais aussi le code dans l'objet observable�;
  • toute r�action destin�e � apparaitre dans une UI (AWT, Swing, JavaFX, etc.) devra �tre effectu�e dans le thread courant de cette UI (Event Dispatch Thread, JavaFX Application Thread, etc.) et non pas dans celui de l'objet observable.

Mis � jour le 14 octobre 2015 bouye

Parfois, on veut qu'un observateur puisse ��consommer�� un �v�nement et emp�cher sa propagation aux observateurs suivants. Rien n'est d�fini dans l'API �v�nementielle de base pour prendre en charge une telle fonctionnalit�. Cependant les �v�nements AWT, Swing et JavaFX disposent d'un m�canisme de s�maphore qu'il est ais�ment possible de reproduire�:

�v�nement
On introduit dans l��v�nement un s�maphore qui permet d'indiquer si on d�sire que la notification puisse continuer � se propager.

Code Java : S�lectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public final class TotoEvent extends EventObject { 
  
    [...] 
  
    private boolean consumed = false; 
  
    /** 
     * Consomme l��v�nement. 
     */ 
    public void consume() { 
        consumed = true; 
    } 
  
    /** 
     * Indique si l��v�nement a �t� consomm�. 
     * @return {@code True} si le test est v�rifi�, {@code false} sinon. 
     */ 
    public boolean isConsumed() { 
        return consumed; 
    } 
}

Observateur
L'observateur qui d�sire consommer l��v�nement et stopper la propagation n'a d�sormais plus qu'� invoquer la m�thode consume() de l��v�nement.

Code Java : S�lectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
public class AnObserver implements TotoListener { 
  
    [...] 
  
    @Override 
    public void totoEventReceived(TotoEvent event) { 
        // G�rer l��v�nement. 
        [...] 
        // Consommer l��v�nement pour emp�cher la propagation. 
        event.consume(); 
    } 
}

Observable
L'objet observable doit s'assurer de bien stopper la propagation lorsque l��v�nement a �t� consomm�. Quand c'est le cas, la m�thode isConsumed() de l��v�nement retourne alors la valeur true.

Code Java : S�lectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
protected void fireTotoEvent() {  
    TotoEvent event = null;  
    int listSize = listenerList.size();  
    // On parcourt la liste � rebours.  
    for (int index = listSize - 2; index >= 0; index -= 2) {  
        // Seules les instances de TotoListener nous int�ressent.  
        if (listenerList.get(index) == TotoListener.class) {  
            // On cr�e l'objet event de mani�re "lazy" (paresseuse), uniquement quand on en a vraiment besoin.  
            if (event == null) {  
                event = new TotoEvent(this);  
            }  
            TotoListener listener = (TotoListener)listenerList.get(index + 1);  
            // On invoque la notification appropri�e sur le listener.  
            listener.totoEventReceived(event);  
            // si l'event a �t� consomm�, on arr�te la propagation. 
            if (event.isConsumed()) { 
                break;  
            } 
        }  
    }  
}

Mis � jour le 14 octobre 2015 bouye

Proposer une nouvelle r�ponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plut�t sur le forum de la rubrique pour �a


R�ponse � la question

Liens sous la question
pr�c�dent sommaire suivant
 

Les sources pr�sent�es sur cette page sont libres de droits et vous pouvez les utiliser � votre convenance. Par contre, la page de pr�sentation constitue une �uvre intellectuelle prot�g�e par les droits d'auteur. Copyright � 2025 Developpez Developpez LLC. Tous droits r�serv�s Developpez LLC. Aucune reproduction, m�me partielle, ne peut �tre faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'� trois ans de prison et jusqu'� 300 000 � de dommages et int�r�ts.