Este documento describe la gestión de eventos con AWT/Swing en Java. Explica el modelo de eventos de Java, la jerarquía de clases de eventos, y cómo crear clases escuchadoras de eventos y asignarlas a fuentes de eventos para manejar acciones del usuario. También cubre temas como clases anónimas, adapters y el patrón Observer relacionado con la gestión de eventos.
1. 7. Gestión de eventos con AWT/Swing
Qué es Gestión de Eventos
El hilo Swing
Modelo de Eventos Java
Jerarquía de Eventos
Clases anónimas y Adapters
Ejemplos
Programación III Tema 6 - Ventanas
2. Modelos de Gestión de
Eventos
• Programación Tradicional:
– No existen modelos de gestión de eventos.
– Programa: Mediante un bucle (polling)
– Ejemplo: Si se pulsa ENTER, sólo se detecta si se hace un getChar()
• Programación en Java (y en otros lenguajes actuales)
– Programación multihilo implícita (2 threads)
• Un flujo de control para el programa, otro para las ventanas
– Modelos de eventos definidos
– El programa es "avisado" automáticamente de todas aquellas
acciones (eventos) en los que esté interesado.
• Para ello debe definirse previamente qué acciones “interesa escuchar”
• El flujo de control que ejecuta el evento es el de las ventanas
– Ejemplo: Si el usuario pulsa un botón, el entorno es capaz de avisar
al programa haciendo una llamada a un método. Para ello, el botón
(el origen del evento) debe conocer al programa (el escuchador del
evento).
Programación III Tema 6 - Ventanas
3. ¿Qué hace (el hilo) Swing?
• En cuanto se crea y visualiza la primera
ventana, Swing se encarga de:
– "Pintar" las ventanas
• Las redibuja si se redimensionan, cambian, se pone
una por delante...
– Gestionar el ratón y el teclado con relación a las
ventanas
– Generar los eventos necesarios
• Pulsaciones de botones
• Paso de ratón por los componentes
• Cambios en ventanas
• etc.
Programación III Tema 6 - Ventanas
4. Modelo de Eventos Java (1)
• Distingue dos elementos:
– Fuentes de Eventos: elementos sobre los que se producen los eventos
(botón, lista, panel...)
• Cualquier componente de AWT (o SWING) sobre el que se puedan producir
eventos (prácticamente todos)
– Escuchadores de Eventos: elementos que reciben las notificaciones de los
eventos
• Cualquier objeto (perteneciente a una clase) que implemente alguno de los
interfaces definidos en Java para la notificación de los eventos.
• Funcionamiento:
– Una “Fuente de Eventos” puede tener asignado un “Escuchador de Eventos”
(o varios) que recibirá las notificaciones de sus eventos.
– Cuando se produce un evento sobre la fuente de eventos, su escuchador es
informado.
– Para ello, se invoca el método que el escuchador tenga definido para la
notificación de ese tipo de evento.
– El escuchador, dentro de ese método, contendrá el código necesario para
tratar ese evento.
• ¿Cómo se asigna un escuchador a una fuente de eventos?
<FuenteEvento>.add<EventoListener>( <Obj.Escuchador> )
Programación III Tema 6 - Ventanas
6. Modelo de Eventos Java (3):
Interfaces
• Interfaces para la notificación de eventos
– Interfaces que contienen métodos (que reciben un objeto evento) que
serán invocados cuando se produzca un determinado tipo de evento.
– Cada interfaz está especializado en capturar un tipo de eventos
determinado.
– Lista de algunas Interfaces y sus métodos:
Interfaz Métodos
ActionListener actionPerformed(ActionEvent)
FocusListener focusGained, focusLost(FocusEvent)
TextListener textValueChanged(TextEvent)
KeyListener keyPressed, keyReleased, keyTyped(KeyEvent)
MouseListener mouseClicked, mousePressed, mouseReleased, mouseEntered,
mouseExited(MouseEvent)
MouseMotionListener mouseDragged, mouseMoved(MouseEvent)
WindowListener windowActivated, windowClosed, windowClosing, windowDeactivated,
windowDeiconified, windowIconified, windowOpened(WindowEvent)
Programación III Tema 6 - Ventanas
7. Jerarquía de Eventos (1)
– Los métodos de las interfaces, además de ser llamados, reciben un
objeto evento que contiene la información que pueda ser relevante.
– Los objetos de tipo “Evento” están organizados en una jerarquía de
clases de eventos:
Programación III Tema 6 - Ventanas
8. Jerarquía de Eventos (2)
– Padre de todos los eventos: EventObject
– Padre de eventos gráficos: AWTEvent
– Cada objeto posee información sobre el evento concreto que se ha
producido.
• Obtención de la información de un evento:
– Cada tipo de evento posee métodos para consultar la información
del evento ocurrido. Ejemplos:
• Clase EventObject
– getSource(): devuelve el objeto (fuente) sobre el que se ha producido el
evento
• Clase ActionEvent
– getModifiers(): información variada sobre el evento (por ejemplo, comb. de
teclas pulsadas –shift, alt-)
• Clase MouseEvent
– getModifiers(): información variada sobre el evento (p ej. el botón pulsado)
– getX() y getY(): coordenada pulsación de ratón
– getClickCount(): número de clicks seguidos efectuados
Programación III Tema 6 - Ventanas
9. Jerarquía de Eventos (3)
– Cada fuente de eventos, generará distintos tipos posibles
de eventos:
Componente Evento Hecho que lo genera
Button ActionEvent El usuario hace un clic sobre el botón
Checkbox ItemEvent El usuario selecciona o deselecciona el Checkbox
List ActionEvent El usuario hace doble click sobre un elemento de la lista
ItemEvent El usuario selecciona o deselecciona un elemento de la lista
Component MouseEvent El usuario pulsa o suelta un botón del ratón, el cursor del
ratón entra o sale o el usuario mueve o arrastra el ratón
FocusEvent El componente gana o pierde el foco
KeyEvent El usuario pulsa o suelta una tecla
TextField ActionEvent El usuario termina de editar el texto (hace un intro)
Window WindowEvent La ventana se abre, se cierra, se minimiza, se reestablece o
se cierra.
Programación III Tema 6 - Ventanas
10. Ej. (1): Ventana y escuchador
• Ventana con un botón y una etiqueta. Cuando se
pulse el botón queremos que en la etiqueta se
visualice la fecha y hora actual.
• Pasos:
– Crear la ventana y todos sus componentes.
– Crear un objeto escuchador que sea capaz de atender a
los eventos generados al pulsar un botón.
• Evento generado: ActionEvent
• Interfaz que posee los métodos para atender ese evento:
ActionListener
– Asignar ese escuchador al botón.
– Incorporar el código a ejecutar cuando se pulse el botón.
Ejemplo: VentanaBoton
Programación III Tema 6 - Ventanas
11. Ejemplos (1b): Hilos
• Aprovechando este ejemplo, veamos cómo
funcionan esos dos hilos
– A la vez que el main() sigue haciendo cosas
– Un evento las puede hacer también
• Escribir a un TextArea
– Cálculo
– Botón
Programación III Tema 6 - Ventanas
12. Ej (2): Escuchador =
Ventana
• ¿Quién debe ser el escuchador? Hay multitud de
enfoques.
– Puede ser una clase que ya hayamos creado (recordar que
se pueden implementar tantas interfaces como se quiera).
Por ejemplo la propia ventana.
public class VentanaBotonEscuchador
extends JFrame
implements ActionListener
– Puede ser otra clase completamente nueva que sólo se
encargue de ser escuchadora. El principal problema está
en acceder a la información/recursos que se puedan
necesitar para tratar el evento correctamente.
– Clase anónimas. Clases que ya proporciona Java que
permiten una gestión simple y limpia de los eventos. Un
enfoque sencillo aunque sorprendente a primera vista.
Ejemplo: VentanaBotonEscuchador
Programación III Tema 6 - Ventanas
13. Ej (3): Escuchador de varios eventos
– Ejemplo: ventana con tres botones y una etiqueta.
– Si tres botones un mismo escuchador ¿cómo saber en el
actionPerformed( ) el botón pulsado?
– Solución: alternativa sobre el evento
public void actionPerformed(ActionEvent e)
{
JButton botonPulsado = (JButton)e.getSource();
if (botonPulsado == boton1)
etiqueta.setText("Se ha pulsado el botón 1");
if (botonPulsado == boton2)
etiqueta.setText("Se ha pulsado el botón 2");
if (botonPulsado == boton3)
etiqueta.setText("Se ha pulsado el botón 3");
}
Ejemplo: VentanaBotones
Programación III Tema 6 - Ventanas
14. Ej (4): Varios eventos desde dist tipo
– Tenemos una ventana con tres botones, una caja de
texto y una etiqueta.
– En este caso, ¿cómo averiguamos si el elemento sobre el
que se produce el evento es un botón o la caja de texto?
– Del mismo modo
...
boton3.addActionListener(this);
texto.addActionListener(this);
...
public void actionPerformed(ActionEvent e)
{
Object elemento = e.getSource();
...
if (elemento == texto)
etiqueta.setText(“Texto rellenado: " +
texto.getText());
... Ejemplo: VentanaBotonesTexto
Programación III Tema 6 - Ventanas
15. Ej (5): Conocer el tipo de
comp.
• Si en algún momento necesitásemos conocer el tipo al que pertenece
alguno de los objetos, podríamos hacer
Object elemento = e.getSource();
if (elemento instanceof JButton)
{
System.out.println("El elemento es un botón");
JButton boton = (JButton)elemento;
}
if (elemento instanceof JTextField)
{
System.out.println("El elemento es de texto");
JTextField cajaTexto = (JTextField)elemento;
}
• ¿Qué ventaja ofrece esta última opción?
• Ejemplo Completo
• Botones (lo ya visto)
• Ratón sobre un panel. Evento: MouseEvent - Interfaz: MouseListener
• Eventos de ventana (cerrar, minimizar, maximizar...)
– Evento: WindowEvent - Interfaz: WindowListener
– Acción a realizar: cerrar la ventana y terminar el programa.
Ejemplo: VentanaEventos
Programación III Tema 6 - Ventanas
16. Adapters (1/2)
• Cuando un listener tiene muchos eventos, como
por ejemplo el MouseListener, hay que redefinir
todos los métodos, aunque sólo se necesite uno de
ellos.
• Para evitar esto, el API ofrece una clase Adapter
para cada listener, en donde ya están redefinidos
los métodos del interfaz listener correspondiente.
• Podemos utilizar una clase que herede de un
Adapter para el tratamiento de los eventos de una
forma más cómoda.
• Esta clase debe ser interna al JFrame, para
poder acceder a sus elementos.
Ejemplo: VentanaEventosConAdapter
Programación III Tema 6 - Ventanas
17. Adapters (2/2)
• Esta clase interna, también se puede definir
de forma anónima:
this.addWindowListener( new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
• Muchos entornos de desarrollo, que generan código
de manera automática para la gestión de eventos, lo
hacen utilizando una clase interna y anónima.
Ejemplo: VentanaEventosConAdapterAnonimo
Programación III Tema 6 - Ventanas
18. Nota: patrón Observer
• El concepto de escuchador responde a un
patrón de diseño más general: Observer
– Un objeto, llamado sujeto, mantiene una lista
de sus objetos observadores
– Cada vez que hay un determinado cambio de
estado en el sujeto, este notifica a sus
observadores
• Llamando a un método particular
• Pasando información con sus parámetros
– Suele concretarse en cumplir un interfaz
• Se puede hacer con punteros a función en otros
lengs.
Programación III Tema 6 - Ventanas
19. Ejemplos de Observer
– Objeto/operación que progresa
• IProgresa{ void progresa( double p ); }
– Objeto/operación que acaba
• IAcaba{ void acabo(); }
– Objeto/estructura que se puede recorrer
• IProcesaRecorrido{ void procesa( Object o ); }
– Objeto que muta/cambia
• IMutacionListener{ void haMutado( ... ); }
• Posible ejemplo: carpeta de disco
– Recorrido de ficheros - progresa + opera + acaba
– Observador de carpeta que cambia (sus fichs.)
Programación III Tema 6 - Ventanas
20. Ejemplo Observer (cont)
public class ProcesoFicheros
public ProcesoFicheros( String path ) ...
public void recorre( IProcesaRecorrido rec,
IProgresa prog, IAcaba fin ) ...
public void addCambioCarpetaListener(
ICambioCarpListener esc ) ...
}
– En el recorrido llamará a:
• rec.procesa( <cada fichero> )
• prog.progresa( <% de vez en cuando> )
• fin.acabo() // al final
– Al añadir un escuchador de cambio llamará a:
• esc.haCambiado( <info de cambio> ) // cada cambio
Programación III Tema 6 - Ventanas
21. Concurso: ProcesoFicheros
• Premio para el mejor: ¡1,5 puntos!
– Posibles "accesits" para otros mejores
• Fecha tope: 18 de noviembre
• Condiciones
– Interfaz visual ventana para seguir la búsqueda
• Lanzamiento de búsqueda - config. de path
• Barra de progreso
• Información de ficheros encontrados
• Lanzamiento de escucha / info. popup de cambios
– Todo el código propio excepto uso de API Java6
– Bien documentado javadoc
Programación III Tema 6 - Ventanas