Tutorial de Java

Creación de Eventos Propios

Anterior | Siguiente
Tras la amplia introducción a la clase AWTEventMulticaster que se ha visto, se puede atacar la creación y envío de eventos propios, que esencialmente consta de las siguientes fases:
  • Definir una clase para que los objetos del nuevo tipo de evento puedan ser instanciados. Debería extender la clase EventObject.
  • Definir un interfaz EventListener para el nuevo tipo de evento. Este interfaz debería ser implementado por las clases Listener del nuevo tipo y debería extender a EventListener.
  • Definir una clase Listener que implemente el interfaz para el nuevo tipo de evento.
  • Definir una clase para instanciar objetos capaces de generar el nuevo tipo de evento. En el ejemplo que se verá a continuación, se extiende la clase Component.
  • Definir un método add<nombre_del_evento>Listener() para que pueda mantener la lista de objetos Listener registrados para recibir eventos del nuevo tipo.
  • Definir un método que envíe un evento del nuevo tipo a todos los objetos Listener registrados en la lista anterior, invocando al método de cada uno de esos objetos. Este método es un método declarado en el interfaz EventListener para el nuevo tipo de evento.

El modelo de Delegación de Eventos puede soportar el registro de múltiples objetos Listener sobre un solo objeto generador de eventos. El modelo también puede soportar el registro de objetos desde una sola clase Listener sobre múltiples objetos generadores de eventos. Y también, el modelo puede soportar combinaciones de los dos.

En la sección anterior se presentó el método add() de la clase AWTEventMulticaster para crear y mantener una lista de objetos Listener registrados. Desafortunadamente, este método no puede utilizarse directamente para mantener una lista de objetos registrados para los eventos creados por el usuario, porque no hay una versión sobrecargada del método cuya signature coincida con el evento nuevo.

Una forma de crear y mantener estas listas de objetos registrados es embarcarse en un ejercicio de programación de estructuras de datos en una lista. Hay ejemplos de esto en algunos libros, pero aquí no se va a ver, porque parece más interesante una aproximación distinta, que consistirá en la construcción de subclases de AWTEventMulticaster y sobrecargar el método add() para que tenga una signature que coincida con el evento que se está creando. Por supuesto, el cuerpo del método sobrecargado todavía tiene que proporcionar código para porcesar la lista, lo cual lo hace de nuevo complicado. Así que, el siguiente ejemplo, se limita a tener un solo objeto registrado, para evitar la dificultad añadida que supondría, en un primer contacto por parte del lector con este tipo de eventos, el encontrarse con el código de proceso de la lista de eventos.

El programa de ejemplo, java1113.java, muestra como se crean, se capturan y se procesan eventos creados por el programador, capacidad que ya se ha introducido en la sección anterior.

Se define una clase NoVisual, cuyos objetos son capaces de generar eventos del nuevo tipo que se va a crear siguiendo los pasos que se han indicado en párrafos anteriores. En el programa, se instancian dos objetos de la clase NoVisual y se define una clase MiClaseEventListener que implementa el interfaz MiEventoListener y define un método para procesar los objetos de tipo MiEvento llamando al método capturarMiEvento().

Los objetos de la clase MiClaseEventListener son instanciados y registrados para recibir eventos propios desde los objetos NoVisual, es decir, se instancian y registran objetos desde una sola clase Listener sobre múltiples objetos generadores de eventos. El objeto NoVisual contiene un método de instancia llamado generarMiEvento(), diseñado para enviar un evento del nuevo tipo al objeto Listener registrado sobre el objeto fuente al invocar el método capturarMiEvento() del objeto Listener.

El método generarMiEvento() es invocado sobre ambos objetos NoVisual, haciendo que se generen los eventos y que sean capturados y procesados por los objetos registrados de la clase MiClaseEventListener. El procesado del evento es muy simple. El identificador y la fuente de la información se extraen del objeto MiEvento que es pasado como parámetro al método capturarMiEvento() y se presenta esta información en la pantalla.

Como en ejemplos anteriores, ahora es el momento de revisar y comentar las líneas de código que resultan más interesantes, o que son nuevas, y merecen un repaso de entre todo el código del ejemplo. El primer fragmento de código en el que hay que reparar es la definición de la clase desde la cual se pueden instanciar los eventos del nuevo tipo. Esta clase extiende la clase EventObject y se reproduce a continuación.

class MiEvento extends EventObject {
    // Variable de instancia para diferencia a cada objeto de este tipo
    String id;

    // Constructor parametrizado
    MiEvento( Object obj,String id ) {
        // Se le pasa el objeto como parametro a la superclase
        super( obj );
        // Se guarda el identificador del objeto
        this.id = id;
        }

    // Método para recuperar el identificador del objeto
    String getEventoID() {
        return( id );
        }
    }

El constructor de la clase recibe dos parámetros. El primero es una referencia al objeto que ha generado el evento, que es pasada al constructor de la superclase, EventObject, donde se almacena para poder acceder a ella a través del método getSource() de esa superclase EventObject. El segundo parámetro es una cadena de identificación proporcionada al constructor cuando el objeto MiEvento es instanciado. En este ejemplo, este identificador es simplemente un String almacenado en una variable de instancia en el objeto fuente cuando se instancia, pero se puede pasar cualquier identificación o comando de este modo. La clase también proporciona un método para poder recuperar esa identificación de la variable de instancia del objeto.

El siguiente código interesante es la definición del nuevo interfaz Listener llamado MiEventoListener que extiende a EventListener. Este interfaz declara el método capturarMiEvento() que es el principal en el procesado de eventos de este tipo.

interface MiEventoListener extends EventListener {
    void capturarMiEvento( MiEvento evt );
    }

El código que se reproduce a continuación es el que implementa el interfaz anterior y define una clase receptora de eventos del nuevo tipo. La clase Listener sobreescribe el evento capturarMiEvento() declarado en el interfaz y utiliza los métodos de la superclase para acceder y presentar en pantalla la identificación del evento y del objeto que lo ha generado.

class MiClaseEventListener implements MiEventoListener {
    public void capturarMiEvento( MiEvento evt ) {
        System.out.println(
            "Metodo capturarMiEvento() invocado sobre " + 
            evt.getEventoID() );
        System.out.println(
            "El origen del evento fue " + evt.getSource() );
        }
    }

En el fragmento que sigue es donde se define la clase NoVisual que extiende la clase Component y mantiene dos variables de instancia; una de ellas es el identificador String inicializado por el constructor de la clase y la otra es una referencia al objeto Listener registrado sobre la fuente de eventos.

class NoVisual extends Component {
    // El identificador de este objeto
    String ID; 
    // Referencia al receptor unico
    MiClaseEventListener miReceptor;

El código siguiente es el que registra un objeto Listener y que, como se puede observar es muy similar al de ejemplos anteriores, excepto que no se utiliza el método add() de la clase AWTEventMulticaster para crear y mantener la lista de objetos registrados. Este código soporta solamente un objeto Listener registrado y contiene la lógica para concluir la ejecución si se intenta registrar más de un objeto receptor de eventos.

public void addMiEventoListener( MiClaseEventListener receptor ) {
    // No se permite que intente incorporar mas de un receptor
    if( miReceptor == null ) 
        miReceptor = receptor;
    else {
        System.out.println( "No se soportan multiples Receptores" );
        // Se sale, si se intentan registrar varios objetos Receptor
        System.exit( 0 );
        }
    }

Y ya sólo resta repasar el código que corresponde al método que genera el evento del nuevo tipo. En este caso, la generación de eventos va acompañada de la invocación del método capturarMiEvento() del objeto Listener registrado al que se le pasa un objeto de tipo MiEvento como parámetro, que es la forma típica de lanzar eventos en el nuevo Modelo de Delegación de eventos del JDK.

public void generarMiEvento() {
    miReceptor.capturarMiEvento( new MiEvento( this,ID ) );
    }

Navegador

Home | Anterior | Siguiente | Indice | Correo