## Manejo de Eventos

Cuando el usuario actúa sobre un componente -- pulsando el ratón o la tecla Return, por ejemplo -- se crea un objeto Event. El sistema manejador de eventos del AWT pasa el Evento a través del árbol de componentes, dando a cada componente una oportunidad para reaccionar ante el evento antes de que el código dependiente de la plataforma que implementan todos los componentes lo procese.

Cada manejador de eventos de un componente puede reaccionar ante un evento de alguna de estas formas:

- Ignorando el evento y permitiendo que pase hacia arriba en el árbol de componentes. Esto es lo que hace la implementación por defecto de la clase Component. Por ejemplo, como la clase TextField y su superclase TextComponent no implementan manejadores de eventos, los Campos de texto obtienen la implementación por defecto de la clase Component. Así cuando un TextField recibe un evento, lo ignora y permite que su contenedor lo maneje.

- Mediante la modificación del ejemplar de Event antes de dejarlo subir por el árbol de componentes. Por ejemplo, una sublcase de TextField que muestra todas las letras en mayúsculas podría reaccionar ante la pulsaicón de una letra minúscula cambiando el Event para que contuviera la versión mayúscula de la letra.

- Reacionando de alguna otra forma ante el evento. Por ejemplo, una sublcase de TextField (o un contenedor de TextField) podrían reaccionar ante la pulsación de la tecla Return llamando a un método que procese el contenido del campo.

- Interceptando el evento, evitando un procesamiento posterior. Por ejemplo, un carácter no válido se ha introducido en un campo de texto, un manejador de eventos podría parar el evento resultante y evitar su propagación. Como resultado, la implementación dependiente de la plataforma del campo de texto nunca vería el evento.

Desde el punto de vista de un Componente, el sistema de manejo de eventos del AWT es como un sistema de filtrado de eventos. El código dependiente de la plataforma genera un evento, pero los Componentes tienen una oportunidad para modificar, reaccionar o interceptar el evento antes de que el código dependiente de la plataforma los procese por completo.

Nota: En la versión actual, los eventos del ratón se envían a los Componentes después de que los haya procesado el código dependiente de la plataforma. Por eso aunque los Componentes pueden interceptar todos los eventos del teclado, actualmente no pueden interceptar los eventos del ratón.

Aunque el AWT define una amplia variedad de tipos de eventos, el AWT no ve todo lo que ocurre. De este modo no todas las acciones del usuario se convierten en eventos. El AWT sólo puede ver aquellos eventos que le deja ver el código dependiente de la plataforma. Por ejemplo, los campos de texto Motif no envían los movimientos del ratón al AWT. Por esta razón, las subclases de TextField y los contenedores no pueden contar con obtener los eventos de movimiento del ratón -- en Solaris, al menos, no hay una forma sencilla de conocer que ese evento se ha producido, ya que no recibe ningún evento cuando se mueve el ratón. Si se quiere acceder a un amplio rango de tipos de eventos se necesitará implementar una subclase de Canvas, ya que la implementación dependiente de la plataforma de la clase Canvas reenvia todos los eventos.

### El Objeto Event

> Cada evento resulta en la creacción de un objeto Event. Un objeto Event incluye la siguiente información:
> - El tipo del evento -- por ejemplo, una pulsación de tecla o un click del ratón, o un evento más abstracto como "acción" o iconificación de una ventana.

> - El objeto que fue la "fuente" del evento -- por ejemplo, el objeto Button correspondiente al botón de la pantalla que pulsó el usuario, o el objeto TextField en el que el usuario acaba de teclear algo.

> - Un campo indicando el momento en que ocurrió el evento.

> - La posición (x,y) donde ocurrió el evento. Esta posición es relativa al origen del Componente a cuyo manejador de eventos se pasó este evento.

> - La tecla que fue pulsada (para eventos de teclado).

> - Un argumento arbitrario (como una cadena mostrada en el Componente) asociada con el evento.

> - El estado de las teclas modificadoras, como Shift o Control, cuando ocurrió el evento.

### Cómo implementar un Manejador de Eventos

> La clase Component define muchos métodos manejadores de eventos, y se puede sobreescribir alguno de ellos. Excepto el método utilizado para todos los propósitos handleEvent()), cada método manejador de eventos sólo puede ser utilziaro para un tipo de evento particular. Recomendamos que se evite el método multi-propósito, si es posible, y en su lugar se sobreescriba el método de manejo de evento que está especificado por el tipo de evento que se necesita manejar. Esta aproximación tiende a tener menor número de efectos laterales adversos.

> La clase Component define los siguientes métodos para responder a los eventos (el tipo de evento manejado se lista después del nombre del método):

> - action() (Event.ACTION_EVENT)
> - mouseEnter() (Event.MOUSE_ENTER)
> - mouseExit() (Event.MOUSE_EXIT)
> - mouseMove() (Event.MOUSE_MOVE)
> - mouseDown() (Event.MOUSE_DOWN)
> - mouseDrag() (Event.MOUSE_DRAG)
> - mouseUp() (Event.MOUSE_UP)
> - keyDown() (Event.KEY_PRESS or Event.KEY_ACTION)
> - keyUp() (Event.KEY_RELEASE or Event.KEY_ACTION_RELEASE)
> - gotFocus() (Event.GOT_FOCUS)
> - lostFocus() (Event.LOST_FOCUS)
> - handleEvent() (all event types)

> Cuando ocurre un evento, se llama al método manejador de evento que coincide con el tipo del evento. Especificamente, el Evento se pasa primero al método handleEvent(), que (en la implementación por defecto de handleEvent()) llama al método apropiado por el tipo de evento.

> El método action() es un método especialista importante en el manejo de eventos. Sólo los componentes de control básicos -- Button, Checkbox, Choice, List, MenuItem, y TextField objects -- producen eventos action. Ellos lo hacen cuando el usuario indica de alguna forma que el control debería realizar alguna acción. Por ejemplo, cuando el usuario pulsa un botón, se genera un evento action. Mediante la implementación del método action(), se puede reaccionar a las acciones sobre los controles sin preocuparse por el eventos de bajo nivel, como la pulsación de tecla o el click del ratón que causó la acción.

> Todos lo métodos manejadores de eventos tienen al menos un argumento (el objeto Event) y devuelven un valor booleano. El valor de retorno indica si el método a manejado completamente el evento. Devolviendo false, el manejador indica que se debe continuar pasando el evento a través del árbol de componentes. Devolviendo true, el manejador indica que el evento no debe seguir pasandose. El método handleEvent() casi siempre deberá devolver super.handleEvent(), para asegurarse que todos los eventos sean pasados al método manejador de eventos apropiado.

> Importante: Como los métodos de dibujo, todos los métodos manejadores de eventos deben ejecutarse rápidamente! De otra fomra, destruirían el rendimiento percibido del programa. Si se necesita realizar alguna operación lenta como resultado de un evento, házlo arrancando otro thread (o enviándo una petición a otro thread) para que realice la operación. Puedes ver Threads de Control.

> En el programa de ejemplo, todo el manejo de eventos lo realizan los objetos ConversionPanels. Utilizan el método action() para capturar los eventos resultantes de las acciones del usuario los campos de texto (TextField), y las listas desplegables (Choice). Para capturar los eventos resultantes de la acción del usuario sobre las barras deslizantes (Scrollbar), deben utilizar el método handleEvent(), ya que los Scrollbars no producen el evento action y la clase Component no define ningún método específico para los eventos de los objetos Scrolbar.

> Aquí tienes la implemtación de ConversionPanel para los método action() y handleEvent():

>     /** Responde a las acciones del usuario sobre los controles. */
>     public boolean action(Event e, Object arg) {
>         if (e.target instanceof TextField) {
>             setSliderValue(getValue());
>             controller.convert(this);
>             return true;
>         }
>         if (e.target instanceof Choice) {
>             controller.convert(this);
>             return true;
>         }
>         return false;
>     }

>     /** Responde a la barra deslizable. */
>     public boolean handleEvent(Event e) {
>         if (e.target instanceof Scrollbar) {
>             textField.setText(String.valueOf(slider.getValue()));
>             controller.convert(this);
>         }
>         return super.handleEvent(e);
>     }

Estos métodos simplemente se aseguran que la barra deslizante y el campo de texto de los ConversionPanel muestren el mismo valor, y le piden al objeto Converter que actualice el otro ConversionPanel. El método action() devuelve true si ha manejado el evento. Esto evita que el evento haga un viaje innecesario a través del árbol de componentes. Si el método action() no puede manejar el evento, devuelve false, para que algún componente superior en el árbol de componentes pueda echarle un vistazo al evento. El método handleEvent() siempre devuelve super.handleEvent() para que todos los eventos sean completamenten procesados.

Una Nota sobre el Método action(): Los eventos Action son eventos de alto nivel. Son causados por uno o más eventos de bajo nivel como una pulsación de tecla y de ratón. Por esta razón, es correcto devolver true para parar el evento actión antes de que siga subiendo por el árbol de componentes después de haberlo manejado -- el código dependiente de la plataforma ya ha manejado los eventos de teclas o del ratón que ha lanzado la acción, no necesita ver de nuevo el evento action.

Nota: Si handleEvent() devolviera true o false (en lugar de llamar a la implementación de su superclase), el método action() nunca sería llamado. Riesgos como este son una parte de la razón por la que hemos avisado para que se evite la utilización del método handleEvent() a menos que sea absolutamente necesario.

### El Foco del Teclado

> Muchos componentes --incluso que aquellos que operan primordialmente con el ratón, como los botones -- pueden operarse con el teclado. Para que tenga efecto una puslación de tecla sobre un componente, este componente debe tener el foco del teclado.

> En un momento dado, al menos una ventana y un componente de esa ventana pueden tener el foco del teclado. Cómo obtienen las ventanas el foco del teclado depende del sistema. Pero una vez que una ventana a obtenido el foco puede utilizar el método requestFocus() para pedir que un componente obtenga el foco.

> Cuando un componente obtiene el foco se llama a su método gotFocus(). Cuando un componente pierde el foco se llama a su método lostFocus().

Ozito