Está en la página 1de 5

Generación y Propagación de Eventos

Fuentes de eventos.

Una fuente es un objeto que genera un evento y sucede cuando el estado de dicho objeto es
modificado. Las fuentes pueden generar más de un tipo de eventos. Cada fuente tiene que registrar
los listeners para que reciban notificaciones sobre un tipo específico. Cada tipo de evento tiene su
propio método de registro pero la forma general es:

Public void addTypeListener(TypeListener ol)

Donde Type es el nombre del evento y ol es una referencia al listener por ejemplo addKeyListener.
Algunas fuentes solo permiten registrar a un listener. La forma general es
addTypeListener(TypeListener ol) throws java.util.TooManyListenersException. Esto es conocido
como difusión única del evento.

A continuación se listan algunos de los componentes de interfaz de usuario que pueden generar los
eventos descritos en el documento anterior. Además de esos elementos de GUI, cualquier clase
derivada de Component puede generar eventos.

Button, JButton. Genera eventos de tipo ActionEvent cuando se presione el botón.


CheckBox. Genera eventos de tipo ItemEvent cuando se selecciona o se deselecciona un checkbox.
Choice. Genera eventos de tipo ItemEvent cuando cambia una opción.
List. Genera eventos de tipo ActionEvent cuando se hace doble clic sobre un elemento; genera
eventos de tipo ItemElement cuando se selecciona o se deselecciona un elemento.
MenuItem. Genera eventos de tipo ActionEvent cuando se selecciona un elemento de menú; genera
eventos de tipo ItemEvent cuando se selecciona o se deselecciona un elemento de un menú de
opciones.
Scrollbar. Genera eventos de tipo AdjustmentEvent cuando se manipula el scrollbar.
Componentes de tipo Text. Genera eventos de tipo TextEvent cuando el usuario introduce un
carácter.
Window. Genera eventos de tipo WindowEvent cuando una ventana se activa, se cierra, se
desactiva, se minimiza, se maximiza, se abre o se sale de ella.

Clases adaptadoras
Proporciona una implementación vacía de todos los métodos en una interfaz listener de evento y son
útiles cuando se quiere recibir y procesar sólo alguno de los eventos que está gestionando una
interfaz listener de eventos en particular. Por ejemplo, la clase MouseMotionAdapter tiene dos
métodos, mouseDragged( ) y mouseMoved( ) los cuales son métodos definidos por la interfaz
MouseMotionListener. Si sólo estamos interesados en eventos de arrastre de ratón, se puede
simplemente extender MouseMotionAdapter y sobrescribir mouseDragged( ).
Tomemos como ejemplo la siguiente ventana

Y su representación de sus elementos en forma de árbol

Cuando un usuario interactúa con el applet, el sistema Java crea una instancia de la clase Event, y
rellena sus datos miembro con la información necesaria para describir la acción. Es en ese momento
cuando el sistema Java permite al applet controlar el evento. Este control comienza por el
Componente que recibe inicialmente el evento (por ejemplo, el botón que ha sido pulsado) y se
desplaza hacia arriba en el árbol de Componentes, componente a componente, hasta que alcanza al
Contenedor de la raíz del árbol. Durante este camino, cada Componente tiene oportunidad de
ignorar el evento o reaccionar ante él en una (o más) de las formas siguientes:

Modificar los datos miembros de la instancia de Event


 Entrar en acción y realizar cálculos basados en la información contenida en el evento
 Indicar al sistema Java que el evento no debería propagarse más arriba en el árbol
 El sistema Java pasa información del evento a un Componente a través del método
handleEvent() del Componente. Todos los métodos handleEvent() deben ser de la forma:

public boolean handleEvent( Event evt )

Un controlador de eventos solamente necesita una información: una referencia a la instancia de la


clase Event que contiene la información del evento que se ha producido.
El valor devuelto por el método handleEvent() es importante. Indica al sistema Java si el evento ha
sido o no completamente controlado por el controlador. Un valor true indica que el evento ha sido
controlado y que su propagación debe detenerse. Un valor false indica que el evento ha sido
ignorado, o que no ha sido controlado en su totalidad y debe continuar su propagación hacia arriba
en el árbol de Componentes.

Veamos la descripción de una acción con el applet de la figura anterior. El usuario pulsa el botón
"Uno". El sistema runtime del lenguaje Java capturará la información sobre el evento (el número de
clics, la localización del clic, la hora en que se ha producido la pulsación y el Componente que ha
recibido el clic) y empaqueta todos esos datos en una instancia de la clase Event. El sistema Java
comienza entonces por el Componente que ha sido pulsado (en este caso, el botón "Uno") y, a
través de una llamada al método handleEvent() del Componente, ofrece a éste la posibilidad de
reaccionar ante el evento. Si el Componente no controla el evento, o no lo hace completamente
(indicado por un valor de retorno false), el sistema Java presentará la instancia de Event al siguiente
Componente por encima en el árbol (en este caso, una instancia de la clase Panel). El sistema Java
continúa de este mismo modo hasta que el evento es controlado en su totalidad o ya no hay
Componentes a los que informar. En la figura siguiente mostramos el camino recorrido por el evento
en su intento de que algún Componente lo controle.

Cada Componente del applet añade una línea al objeto TextArea indicando que ha recibido un
evento. Luego permite que el evento se propague al siguiente Componente.

El código del controlador de eventos usado en el ejemplo es el que muestran las siguientes líneas:

public boolean handleEvent( Event evt) {


if( evt.id == Event.ACTION_EVENT )
ta.appendText( "Panel " + str + " recibe action...\n" );
else if( evt.id == Event.MOUSE_DOWN )
ta.appendText( "Panel " + str + " recibe mouse_down...\n" );

return super.handleEvent( evt );


}
Clases internas
Es una clase definida dentro de otra clase o expresión. En este apartado muestra cómo se pueden
utilizar para simplificar el código junto con clases adaptadoras.

Clase adaptadora Interfaz para listener


ComponentAdapter ComponentListener
ContainerAdapter ContainerListener
FocusAdapter FocusListener
KeyAdapter KeyListener
MouseAdapter MouseListener
MouseMotionAdapter MouseMotionListener
WindowAdapter WindowListener

// Este applet NO utiliza una clase interna.


import java.applet.*;
import java.awt.event.*;
/*
<applet code="MousePressedDemo" width=200 height=100>
</applet>
*/
public class MousePressedDemo extends Applet {
public void init() {
addMouseListener(new MyMouseAdapter(this));
}
}
class MyMouseAdapter extends MouseAdapter {
MousePressedDemo mousepressedDemo;
public MyMouseAdapter(MousePressedDemo mousePressedDemo) {
this.mousePressedDemo = mousepressedDemo;
}
public void mousePressed(MouseEvent me) {
mousePressedDemo.showStatus("Se ha presionado el ratón.");
}
}
En este programa hay dos clases de alto nivel. MousePressedDemo que extiende a Applet, y
MyMouseAdapter que extiende a MouseAdapter. El método init( ) de MousePressedDemo instancia
a MyMouseAdapter y pasa ese objeto como un argumento al método addMouseListener( ).
Es importante observar que se pasa una referencia al applet como argumento al constructor
MyMouseAdapter. Esta referencia se guarda en una variable de instancia para que la utilice más
tarde el método mousePressed( ). Cuando se presiona el botón del ratón, se invoca al método
showStatus( ) del applet a través de la referencia al applet que se tenía guardada.
En otras palabras, se invoca a showStatus( ) en función de la referencia guardada por
MyMouseAdapter.

A continuación se muestra cómo se puede mejorar el programa anterior utilizando una clase interna.
Aquí, InnerClassDemo es una clase de nivel superior que extiende a Applet.
MyMouseAdapter es una clase interna que extiende a MouseAdapter. Puesto que se define a
MyMouseAdapter dentro del ámbito de InnerClassDemo, tiene acceso a todos los métodos y
variables dentro del ámbito de esa clase. Por lo tanto, el método mousePressed( ) puede llamar
directamente al método showStatus( ). Al hacer esto, ya no se necesita guardar referencia alguna al
applet. Es decir, ya no es necesario que MyMouseAdapter( ) pase una referencia al objeto invocado.

// Ejemplo de una clase interna.


import java.applet.*;
import java.awt.event.*;
/*
<applet code="InnerClassDemo" width=200 height=100>
</applet>
*/
public class InnerClassDemo extends Applet {
public void init() {
addMouseListener(new MyMouseAdapter());
}
class MyMouseAdapter extends MouseAdapter {
public void mousePressed(MouseEvent me) {
showStatus("Se ha presionado el ratón");
}
}
}

Clases internas anónimas


Es aquella a la que no se le asigna un nombre. En este apartado se muestra cómo es más fácil la
escritura de manejadores de eventos utilizando clases internas anónimas.
// Ejemplo de una clase interna anónima.
import java.applet.*;
import java.awt.event.*;
/*
<applet code="AnonymousInnerClassDemo" width=200 height=l00>
</applet>
*/
public class AnonymousInnerClassDemo extends Applet {
public void init() {
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent me) {
showStatus("Se ha presionado el ratón");
}
});
}
}
La sintaxis new MouseAdapter( ) { ... } indica al compilador que el código que está entre llaves define
una clase interna anónima. Además, esa clase extiende a MouseAdapter. Esta nueva clase no tiene
nombre, pero es automáticamente solicitada cuando se ejecuta esta expresión.

También podría gustarte