Tutorial de Java

Adaptadores

Anterior | Siguiente
Muchos interfaces EventListener están diseñados para recibir múltiples clases de eventos, por ejemplo, el interfaz MouseListener puede recibir eventos de pulsación de botón, al soltar el botón, a la recepción del cursor, etc. El interfaz declara un método para cada uno de estos subtipos. Cuando se implementa un interfaz, es necesario redefinir todos los métodos que se declaran en ese interfaz, incluso aunque se haga con métodos vacíos. En la mayoría de las ocasiones, no es necesario redefinir todos los métodos declarados en el interfaz porque no son útiles para la aplicación.

Por ello, el AWT proporciona un conjunto de clases abstractas adaptadores (Adapter) que coinciden con los interfaces. Cada clase adaptador implementa un interfaz y redefine todos los métodos declarados por el interfaz con métodos vacíos, con lo cual se satisface ya el requerimiento de la redefinición de todos los métodos.

Se pueden definir clases Receptor extendiendo clases adaptadores, en vez de implementar el interfaz receptor correspondiente. Esto proporciona libertad al programador para redefinir solamente aquellos métodos del interfaz que intervienen en la aplicación que desarrolla.

De nuevo, hay que recordar que todos los métodos declarados en un interfaz corresponden a los tipos de eventos individuales de la clase de eventos correspondiente, y que el objeto Fuente notifica al Receptor la ocurrencia de un evento de un tipo determinado invocando al método redefinido del interfaz.

Las clases Adaptadores que se definen en el JDK 1.2 son las que se indican a continuación:

    java.awt.ComponentAdapter 
    java.awt.FocusAdapter 
    java.awt.KeyAdapter
    java.awt.MouseAdapter 
    java.awt.MouseMotionAdapter 
    java.awt.WindowAdapter 

En el ejemplo java1102.java, se modifica el primer programa de este capítulo, en que la ejecución no terminaba cuando se cerraba la ventana; ahora el programa termina cuando el usuario cierra la ventana, ejecutando la sentencia de salida en el controlador de eventos adecuado. El programa implementa un objeto EventSource que notifica a un objeto Listener la ocurrencia de un evento en la clase Window, y notifica a otro objeto Listener la ocurrencia de un evento en la clase Mouse.

Si se compila y ejecuta el ejemplo, cada vez que se pulse el botón del ratón con el cursor dentro de la ventana, aparecerán las coordenadas en las que se encuentra el cursor, tal como muestra la figura anterior.

En el caso más simple, los eventos de bajo nivel del nuevo modelo de Delegación de Eventos, se pueden controlas siguiendo los pasos que se indican a continuación:

  • Definir una clase Listener, receptor, para una determinada clase de evento que implemente el interfaz receptor que coincida con la clase de evento, o extender la clase adaptadora correpondiente
  • Redefinir los métodos del interfaz receptor para cada tipo de evento específico de la clase evento, para poder implementar la respuesta deseada del programa ante la ocurrencia de un evento. Si se implementa el interfaz receptor, hay que redefinir todos los métodos del interfaz. Si se extiende la clase adaptadora, se pueden redefinir solamente aquellos métodos que son de interés
  • Definir una clase Source, fuente, que instancie un objeto de la clase receptor y registrarla para la notificación de la ocurrencia de eventos generados por cada componente específico

Por ejemplo, esto se consigue utilizando código como

    objetoVentana.addMouseListener( procesoRaton );

en donde

objetoVentana es el objeto que genera el evento

procesoRaton es el nombre del objeto receptor del evento, y

addMouseListener es el método que registra el objeto receptor para recibir eventos de ratón desde el objeto llamado objetoVentana

Esta sentencia hará que el objeto procesoRaton sea notificado de todos los eventos que se produzcan sobre el objetoVentana que sean parte de la clase de eventos del ratón. La notificación tendrá lugar invocando al método redefinido en el objeto procesoRaton que corresponda con cada tipo específico de evento en la clase de eventos de ratón, aunque algunos de estos métodos pueden estar vacíos porque no interese tratar los eventos a que corresponden.

Todo lo anterior en el caso más simple, porque es posible complicar la situación a gusto, por ejemplo, si se quiere notificar a dos objetos receptor diferentes de la ocurrencia de un determinado evento sobre un mismo objeto de la pantalla, tal como muestra el código del ejemplo java1103.java, en donde un objeto receptor es compartido por dos componentes visuales diferentes del mismo tipo. El programa detecta los eventos de ratón sobre dos objetos Frame diferentes, que distingue en base a su nombre, y presenta las coordenadas del cursor en cada pulsación sobre el objeto en que se encontraba el cursor.

El código del ejemplo es realmente simple, la única parte críptica es la que trata de obtener el nombre del componente visual que ha generado el evento mousePressed().

El método main() instancia un objeto de tipo IHM, que sirve para dos propósitos, por un lado proporcionar el interfaz visual y, por otro, actuar como una fuente de eventos que notificará su ocurrencia a los objetos receptor que se registren con él.

La clase Frame es extendida en una nueva clase llamada MiFrame, para permitir la redefinición del método paint() de la clase; lo cual es imprescindible para presentar las coordenadas en donde se encuentra el cursor sobre el Frame, utilizando el método drawString().

El constructor de la clase IHM instancia dos objetos de tipo MiFrame y los hace visibles. Cuando son instanciados, se les asignan los nombre Frame1 y Frame2 a través del método setName(). Estos nombres serán los que permitan determinar posteriormente cuál ha sido el objeto que ha generado el evento.

También en ese mismo constructor se instancia a un solo objeto receptor a través del cual se procesarán todos los eventos de bajo nivel que se produzcan en cualquiera de los dos objetos visuales:

    ProcesoRaton procesoRaton = new ProcesoRaton( miFrame1,miFrame2 );
    miFrame1.addMouseListener( procesoRaton ); 
    miFrame2.addMouseListener( procesoRaton ); 

La primera sentencia solamente instancia el nuevo objeto receptor procesoRaton, pasándole las referencias de los dos elementos visuales como parámetro. Las dos sentencias siguientes incorporan este objeto receptor (lo registran) a la lista de objetos receptor que serán automáticamente notificados cuando suceda cualquier evento de ratón sobre los objetos visuales referenciados como miFrame1 y miFrame2, respectivamente. Y ya no se requiere ningún código extra para que se produzca esa notificación.

Las notificaciones se realizan invocando métodos de instancia específicos redefinidos del objeto receptor ante la ocurrencia de tipos determinados de eventos del ratón. Las declaraciones de todos los métodos deben coincidir con todos los posibles eventos del ratón que estén definidos en el interfaz MouseListener, que deben coincidir con los definidos en la clase MouseEvent. La clase desde la que el objeto receptor es instanciado debe redefinir, bien directa o indirectamente, todos los métodos declarados en el interfaz MouseListener.

Además de registrar el objeto MouseListener para recibir objetos de ratón, el programa también instancia y registra un objeto receptor que monitoriza los eventos de la ventana, y termina la ejecución del programa cuando el usuario cierra uno cualquiera de los objetos visuales.

    Proceso1 procesoVentana1 = new Proceso1(); 
    miFrame1.addWindowListener( procesoVentana1 ); 
    miFrame2.addWindowListener( procesoVentana1 ); 

En este caso, el código no intenta distinguir entre los dos objetos visuales.

La parte más complicada de la programación involucra al objeto receptor del ratón, y aún así, es bastante sencilla. Lo que intenta el código es determinar cuál de los dos elementos visuales ha sido el que ha generado el evento. En este caso el objeto receptor solamente a eventos mousePressed, aunque lo que se explica a continuación se podría aplicar a todos los eventos del ratón y, probablemente, a muchos de los eventos de bajo nivel.

La clase ProcesoRaton (receptor) en este programa extiende la clase MouseAdapter y redefine el método mousePressed() que está declarado en el interfaz MouseListener. Cuando es invocado el método mousePressed(), se le pasa un objeto de tipo MouseEvent, llamado evt, como parámetro.

Para determinar si el objeto que ha generado el evento ha sido Frame1, se utiliza la siguiente sentencia:

if( evt.getComponent().getName().compareTo( "Frame1" ) == 0 ) { 

El método getComponent() es un método que devuelve el objeto donde se ha generado el evento. En este caso devuelve un objeto de tipo Component sobre el cual actúa el método getName(). Este último método devuelve el nombre del Componente como un objeto String, sobre el cual actúa el método compareTo(). Este método es estándar de la clase String y se utiliza para comparar dos objetos String. En este caso se utiliza para comparar el nombre del componente con la cadena "Frame1"; si es así, el código que se ejecuta es el que presenta las coordenadas del ratón sobre el objeto visual Frame1; si no coincide se ejecuta el código de la cláusula else que presentará las coordenadas sobre el objeto visual Frame2.

También es posible realizar la comparación directamente sobre el objeto MouseEvent, tal como se verá más adelante. Por ahora, baste hacer ver al lector que el paquete java.awt.event es diferente del paquete java.awt. El paquete java.awt.event ha sido añadido desde el JDK 1.1, aunque se mantiene parte de la documentación por compatibilidad con el JDK 1.0.2. Ha de tenerse cuidado pues a la hora de consultar la documentación, porque puede resultar altamente confuso al lector la consulta si mira la documentación del paquete java.awt cuando lo que necesita mirar se encuentra realmente en la documentación del paquete java.awt.event.

Aunque en el ejemplo anterior se utilizan dos objetos visuales del mismo tipo, no hay razón alguna para que eso sea así, ya que todos los objetos visuales comparten el mismo objeto receptor y son capaces de generar eventos para los que el receptor está registrado.

El ejemplo java1104.java, es una modificación del programa anterior para utilizar un objeto Frame y un objeto Window, en vez de dos objetos Frame, para mostrar cómo un mismo objeto receptor puede recibir eventos de dos fuentes distintas.

Navegador

Home | Anterior | Siguiente | Indice | Correo