Eventos y oyentes

¿Cómo se crea un evento personalizado y cómo se activa para que un componente pueda obtener un evento?

Antes de mirar un evento personalizado, veamos un evento preexistente: el ActionEvent.

Los componentes como Buttony se JButtondisparan ActionEventspara indicar algún tipo de acción definida por el componente. Por ejemplo, se Buttondispara ActionEventcada vez que el usuario lo presiona. El objetivo de un evento es informar a un oyente que algo le ha sucedido a un componente en la GUI. Un evento incluye toda la información que un oyente necesita para averiguar qué sucedió y a quién le sucedió (el qué y quién del evento). Un evento debe proporcionar suficiente información para describirse completamente a sí mismo. De esa manera, un oyente puede descubrir qué sucedió exactamente y responder de manera significativa.

La ActionEventincluye métodos para el aprendizaje de la cadena de la acción de comandos, modificadores, y la cadena de identificación. El getActionCommand()método devuelve la cadena de comando que indica la acción prevista del evento, como imprimir o copiar (el qué). El getSource()método devuelve el objeto que genera el evento (el quién).

Para recibir un ActionEvent, un oyente debe implementar la ActionListenerinterfaz y registrarse con el componente. Además, un componente debe realizar un seguimiento de sus oyentes para notificarles de un evento.

Al usar el ActionEventejemplo como modelo, podemos ver fácilmente las piezas necesarias para que un componente genere un evento y un oyente para escuchar un evento. En un nivel alto, hay tres piezas:

  1. El componente
  2. La clase de evento
  3. La interfaz de escucha

Echemos un vistazo a cada uno por separado.

El componente

Los componentes generan eventos. Un evento es la forma que tiene un componente de hacerle saber a un oyente que algo ha sucedido. Por lo tanto, un componente debe proporcionar un mecanismo para registrar y cancelar el registro de detectores de eventos. El componente también debe rastrear a sus oyentes y transmitir los eventos a esos oyentes.

La mecánica de registro / cancelación de registro y seguimiento se deja al componente individual. Sin embargo, un componente normalmente tendrá un addXXXListenery removeXXXListenerpara cada tipo de evento que genere. Internamente, el componente puede almacenar un oyente como quiera; normalmente, sin embargo, los componentes almacenan oyentes en java.util.Vectoro javax.swing.event.EventListenerList. Para lanzar un evento a sus oyentes, el componente simplemente recorre su lista de oyentes y pasa el evento a cada oyente llamando al método de despacho de eventos del oyente.

Es hora de dar un ejemplo:

... 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 .