Tutorial de Java

La Cola de Eventos del Sistema

Anterior | Siguiente
Una de las cosas más complicadas de entender del nuevo modelo de gestión de eventos es la creación de eventos y el envío de estos eventos a la cola de eventos del Sistema, para que lo lance a un determinado componente. El concepto en sí no es difícil, sin embargo, como la documentación es escasa, se vuelve una ardua tarea el entender el funcionamiento del sistema en esta circunstancia.

En este modelo para la creación y envío de eventos a la cola del Sistema, solamente es necesario invocar a un método, tal como muestra la siguiente sentencia:

Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(
    new MouseEvent( miComponente,MouseEvent.MOUSE_CLICKED,0,0,-1,-1,2,false ) );

Si se examina la sentencia de dentro hacia fuera, se observa que hay una instanciación de un nuevo objeto evento del tipo que se desea; se envía el objeto a la cola de eventos del Sistema que es devuelta por la invocación al método getSystemEventQueue(), que es un método de Toolkit devuelto por la invocación al método getDefaultToolkit(), que es un método estático de la clase Toolkit.

Ahora se presenta el ejemplo java1114.java, en donde se utiliza la cola de eventos del Sistema para interceptar eventos del teclado y convertirlos en eventos del ratón.

El objeto principal del interfaz gráfico es instanciado desde la clase que extiende a la clase Frame. Se crea un componente propio extendiendo un Label. Los objetos de esta nueva clase así creada son capaces de responder a eventos del teclado y del ratón. Extendiendo la clase Label es posible sobreescribir el método processMouseEvent() de la clase Label que se proporciona a la clase MiComponente.

Los eventos del ratón son habilitados sobre los objetos de esta clase para que cualquier evento del ratón sea enviado al método processMouseEvent() y, como siempre en estos casos, hay que pasar el objeto MouseEvent al método del mismo nombre de la superclase antes de que termine el flujo del programa en el método.

Los clicks sobre el ratón con el cursor posicionado en el objeto que se ha creado son eviados al método processMouseEvent() en el cual lo que se hace es presentar la información que contiene el evneto en pantalla.

Los eventos del teclado, KeyEvent, son capturados por el receptor KeyListener. Cuando se captura un evento del teclado se genera un objeto MouseEvent sintético y se coloca en la cola de eventos del Sistema. La documentación del JDK 1.2 para la creación de un objeto MouseEvent es la siguiente:

    public MouseEvent(Component source,
                      int id,
                      long when,
                      int modifiers,
                      int x,
                      int y,
                      int clickCount,
                      boolean popupTrigger)

En el programa que nos ocupa, source es una referencia al objeto que se ha creado. Se asignan valores negativos a los parámetros x e y para que el objeto sea fácilmente reconocible cuando se genere, ya que un click real nunca podrá tener valores negativos en las coordenadas. Para el resto de parámetros se asignan valores aleatorios, excepto para id. Este parámetro es crítico a la hora de crear el objeto MouseEvent ya que debe coincidir con alguna de las constantes simbólicas que están definidas en la clase MouseEvent para los diferentes eventos del ratón que reconoce el Sistema. Estas constantes son:

MOUSE_FIRST Primer entero usado como id en el rango de eventos
MOUSE_LAST Ultimo entero usado como id en el rango de eventos
MOUSE_CLICKED
MOUSE_PRESSED
MOUSE_RELEASED
MOUSE_ENTERED
MOUSE_EXITED
MOUSE_DRAGGED

Si el identificador id asignado al nuevo evento no se encuentra en el rango anterior, no se produce ningún aviso ni se genera ninguna excepción, ni en la compilación ni en la ejecución del programa, simplemente no se envía ningún evento.

Cuando se ejecuta el programa aparece una ventana en la pantalla totalmente ocupada con el componente propio creado al extender la etiqueta. Si se muevo el ratón se producen mensajes normales en la pantalla del sistema generados por el método processMouseEvent(); pero si se pulsa una tecla, aparecerá un mensaje indicando la tecla pulsada y a continuación se indica que hay una llamada al método de procesado de eventos del ratón, al haberse generado un evento sintético provocado por la pulsación de la tecla. En las líneas siguientes se observa la salida por pantalla que se acaba de describir.

Metodo processMouseEvent(), MiComponente ID = 505 java.awt.Point[x=246,y=54]
Metodo processMouseEvent(), MiComponente ID = 504 java.awt.Point[x=239,y=28]
Metodo keyPressed(), tecla pulsada -> x
Metodo processMouseEvent(), MiComponente ID = 500 java.awt.Point[x=-1,y=-1]
Metodo processMouseEvent(), MiComponente ID = 505 java.awt.Point[x=246,y=47]
Metodo processMouseEvent(), MiComponente ID = 504 java.awt.Point[x=227,y=23]
Metodo keyPressed(), tecla pulsada -> y
Metodo processMouseEvent(), MiComponente ID = 500 java.awt.Point[x=-1,y=-1]
Metodo processMouseEvent(), MiComponente ID = 505 java.awt.Point[x=188,y=96]

Echando un vistazo al código del programa se observa que hay gran parte ya vista en ejemplos anteriores; así que, siguiendo la tónica de otras secciones, se revisan a continuación los trozos de código que se han introducido nuevos o que merece la pena volver a ver. El primer fragmento son las sentencias en que se instancia un objeto del tipo MiComponente y se registra un objeto KeyListener para recibir los eventos del teclado sobre ese componente. Posteriormente, será el código de ese receptor KeyListener el que atrapará los objetos KeyEvent, creará objetos MouseEvent sintéticos y los enviará a la cola del Sistema como porvenientes de MiComponente.

MiComponente miComponente = new MiComponente();
this.add( miComponente );
. . . 
miComponente.addKeyListener( new MiKeyListener( miComponente ) );

La sentencia siguiente es la ya vista al comienzo, en la que se proporcionan todos los parámetros necesarios para generar el evento del ratón sintético y enviarlo a la cola de eventos del Sistema. Entre esos parámetros está la referencia al componente creado, que en la descripción anterior era el parámetro source, luego está el parámetro id del nuevo evento, que es uno de la lista presentada antes y, finalmente, están las coordenadas x e y, que se fijan a –1 para poder reconocer fácilmente el evento sintético entre los mensajes que aparezcan por la pantalla.

Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(
    new MouseEvent( miComponente,MouseEvent.MOUSE_CLICKED,0,0,-1,-1,2,false ) );

Lo que ocurre aquí, si se piensa un poco en ello, es que hay un gran problema de seguridad si se permite que applets no certificados manipulen libremente la cola de eventos del Sistema. Por ello, el método getSystemEventQueue() está protegido por comprobaciones de seguridad que impiden a los applets acceso directo a la cola de eventos.

Ahora se encuentra la sentencia que permite la generación de eventos y que está contenida en el constructor de la clase MiComponente. Esta sentencia es necesaria para poder invocar al método sobreescrito processMouseEvent() siempre que un evento de ratón sea enviado a un objeto de la clase MiComponente.

enableEvents( AWTEvent.MOUSE_EVENT_MASK );

Finalmente, para concluir el repaso al código del ejemplo, está el método sobreescrito processMouseEvent() que anuncia la invocación del método y presenta en pantalla información del id del evento y las coordenadas que contiene. La sentencia final es la llamada al mismo método de la superclase, si no se hace esta llamada, la salida probablemente no sea del todo correcta.

public void processMouseEvent( MouseEvent evt ) {
    // Se indica que se ha invocado a este metodo y se presenta
    // el identificador y las coordenadas del objeto MouseEvent 
    // que se haya pasado como parametro
    System.out.println(
        "Metodo processMouseEvent(), MiComponente ID = " + 
        evt.getID() + " " + evt.getPoint() );

    // SIEMPRE hay que hacer esto si se sobreescribe el metodo
    super.processMouseEvent( evt );
    } 

Y el resto del código es el mismo que el de muchos de los ejemplos anteriores.

Navegador

Home | Anterior | Siguiente | Indice | Correo