Événements et auditeurs

Comment créer un événement personnalisé et comment le déclencher pour qu'un composant puisse obtenir un événement?

Avant de regarder un événement personnalisé, examinons un événement préexistant: le ActionEvent.

Des composants tels que Buttonet se JButtondéclenchent ActionEventspour indiquer une sorte d'action définie par le composant. Par exemple, le Buttonse déclenche ActionEventchaque fois que l'utilisateur appuie dessus. Le but d'un événement est d'informer un auditeur que quelque chose est arrivé à un composant dans l'interface graphique. Un événement comprend toutes les informations dont un auditeur a besoin pour comprendre ce qui s'est passé et à qui cela s'est produit (le quoi et qui de l'événement). Un événement doit donner suffisamment d'informations pour se décrire pleinement. De cette façon, un auditeur peut comprendre ce qui s'est exactement passé et répondre de manière significative.

Le ActionEventcomprend des méthodes pour apprendre la chaîne de commande, les modificateurs et la chaîne d'identification de l'action. La getActionCommand()méthode renvoie la chaîne de commande qui indique l'action prévue de l'événement, comme imprimer ou copier (le quoi). La getSource()méthode retourne l'objet qui génère l'événement (le who).

Afin de recevoir un ActionEvent, un auditeur doit implémenter l' ActionListenerinterface et s'enregistrer auprès du composant. De plus, un composant doit garder une trace de ses auditeurs afin de les notifier d'un événement.

En utilisant l' ActionEventexemple comme modèle, nous pouvons facilement voir les éléments nécessaires à un composant pour générer un événement et à un auditeur pour écouter un événement. À un niveau élevé, il y a trois pièces:

  1. Le composant
  2. La classe événement
  3. L'interface auditeur

Jetons un coup d'œil à chacun d'eux séparément.

Le composant

Les composants génèrent des événements. Un événement est la manière dont un composant permet à un auditeur de savoir que quelque chose s'est passé. Par conséquent, un composant doit fournir un mécanisme pour enregistrer et annuler l'enregistrement des écouteurs d'événements. Le composant doit également suivre ses auditeurs et transmettre les événements à ces auditeurs.

Les mécanismes d'enregistrement / de désinscription et de suivi sont laissés au composant individuel. Cependant, un composant aura normalement un addXXXListeneret removeXXXListenerpour chaque type d'événement qu'il génère. En interne, le composant peut stocker un auditeur comme il le souhaite; Cependant, généralement, les composants stockent les écouteurs dans un fichier java.util.Vectorou javax.swing.event.EventListenerList. Pour déclencher un événement sur ses écouteurs, le composant parcourt simplement sa liste d'écouteurs et transmet l'événement à chaque écouteur en appelant la méthode de répartition d'événements de l'écouteur.

Il est temps de donner un exemple:

... EventListenerList xxxListeners = new EventListnerList(); public void addXXXListener(XXXListener listener) { xxxListeners.add(XXXListener.class, listener); } public void removeXXXListener(XXXListener listener) { xxxListeners.remove(XXXListener.class, listener); } protected void fireXXX(XXXEvent xxxEvent) { Object[] listeners = xxxListeners.getListenerList(); // loop through each listener and pass on the event if needed Int numListeners = listeners.length; for (int i = 0; i
    

This example shows how to register, deregister, and fire events of type XXXEvent. Listeners can register and deregister themselves through the addXXXListener() and removeXXXListener() methods. When an event occurs, the component creates an event object and passes it to the fireXXX() method, where it is passed to the listeners.

The example defines a generic recipe that all components can follow. However, in order for the example to work, you must define an XXXEvent and an XXXListener interface.

The event class

The event holds all of the information necessary for a listener to figure out what happened. The information included is really event specific. Just think about the event carefully and design the event class to hold whatever information is necessary to fully describe the event to a listener. Events normally extend the java.awt.AWTEvent event class.

The listener interface

An event listener interface defines the methods used by a component to dispatch events. Each event type will have at least one corresponding dispatch method in a listener interface.

A listener interface takes the following generic format:

public interface XXXListener extends EventListener { // event dispatch methods somethingHappened(XXXEvent e); somethingElseHappened(XXXEvent e); ... } 

To listen for an event, a listener must implement the XXXListener interface and register itself with the component. When an event occurs, the component will call the proper dispatch method. The methods are defined in an interface so that any object can receive the event. As long as the listener implements the interface, the component will know how to dispatch the event to the listener.

Wrap-up

As you can see, there are dependencies between some of the pieces. The listener interface corresponds directly to the event. The event is necessarily the dispatch method's argument.

The component corresponds directly with the event and listener. It needs to know about each so that it can create events, dispatch events, and register listeners.

Unlike the other two pieces, the event object is independent. As a result, many components are free to fire off the event type. Furthermore, multiple interfaces may define methods to dispatch the event.

Tony Sintes is a principal consultant at BroadVision. Tony, a Sun-certified Java 1.1 programmer and Java 2 developer, has worked with Java since 1997.

This story, "Events and listeners" was originally published by JavaWorld .