Tutorial08-gesteventos

17

Click here to load reader

Transcript of Tutorial08-gesteventos

Page 1: Tutorial08-gesteventos

8-1

TEMA 8: GESTIÓN DE EVENTOS

8.1.- GESTIÓN DE EVENTOS En el pasado, un programa que quisiera saber lo que estaba haciendo el usuario, debía recoger la información él mismo. En la práctica, esto significaba que una vez inicializado, el programa entraba en un gran bucle en el que continuamente se bloqueaba para comprobar que el usuario estuviese haciendo algo interesante (por ejemplo, pulsar un botón, pulsar una tecla, mover una barra o mover el ratón) y tomar las acciones oportunas. Esta técnica se conoce como polling.

El polling funciona, pero se vuelve demasiado difícil de manejar con las aplicaciones modernas por dos razones fundamentales: primero, el uso de polling tiende a colocar todo el código de control de eventos en una única localización (dentro de un gran bucle); segundo, las interacciones dentro del gran bucle tienden a ser muy complejas. Además, el polling necesita que el programa esté ejecutando el bucle, consumiendo tiempo de CPU, mientras está esperando a que el usuario se decida a hacer algo, lo que supone un gran despilfarro de recursos.

El AWT resuelve estos problemas abrazando un paradigma diferente, en el que están basados todos los sistemas modernos de ventanas: la orientación a eventos. Dentro del AWT, todas las acciones que pueda realizar el usuario caen dentro de un gran saco que son los eventos. Un evento describe, con suficiente detalle, una acción particular del usuario. En lugar de que el programa activamente recoja todos los eventos generados por el usuario, el sistema Java avisa al programa cuando se produce un evento interesante.

Todo sistema operativo que utiliza interfaces gráficas de usuario debe estar constantemente monitorizando el entorno para capturar y tratar los eventos que se producen. El sistema operativo informa de estos eventos a los programas que se están ejecutando, y entonces cada programa decide qué hace para dar respuesta a esos eventos.

Los eventos pueden estar producidos por el sistema o por el usuario. Por ejemplo, pulsar una tecla o mover el ratón.

El modelo de gestión de eventos es la forma en que se generan, capturan y tratan los eventos.

Modelo de eventos en C

En el lenguaje C, es necesario escribir código para comprobar la cola de eventos que está generando el sistema operativo constantemente. Se escribe código de respuesta a cada evento.

Page 2: Tutorial08-gesteventos

Laboratorio de Informática II – Gestión de Eventos

8-2

Habitualmente se realiza un bucle infinito con una sentencia multialternativa (switch) que decide la respuesta a cada evento.

Es la forma más dura de tratar eventos, ya que hay que programarlo todo, no hay facilidades. La ventaja es que no hay ninguna limitación para tratar eventos, ya que el programador accede directamente a la cola de eventos del sistema.

8.2.- TIPOS DE EVENTOS Cuando el usuario interactúa sobre los diversos componentes del AWT, estos componentes generan eventos. La siguiente tabla muestra los eventos que cada tipo de componente puede generar y cuándo los genera.

Tipo de Componente

Eventos generados Hechos que los generan

Button ActionEvent El usuario hace un clic sobre el botón.

Checkbox ItemEvent El usuario selecciona o deselecciona el interruptor (Checkbox)

CheckboxMenuItem ItemEvent El usuario selecciona o deselecciona el interruptor (Checkbox)

Choice ItemEvent El usuario selecciona o deselecciona un elemento de la lista

ComponentEvent El componente se mueve, cambia de tamaño, se esconde o se exhibe

FocusEvent El componente gana o pierde el foco

KeyEvent El usuario pulsa o suelta una tecla

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

Page 3: Tutorial08-gesteventos

Laboratorio de Informática II – Gestión de Eventos

8-3

Tipo de Componente

Eventos generados Hechos que los generan

Container ContainerEvent Se agrega o se quita un componente al contenedor

ActionEvent El usuario hace doble clic en un elemento de la lista

List

ItemEvent El usuario selecciona o deselecciona un elemento de la lista

MenuItem ActionEvent El usuario selecciona un elemento del menú

Scrollbar AdjustmentEvent El usuario mueve la barra de desplazamiento

TextComponent TextEvent El usuario hace un cambio en el texto

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.

Todos los eventos mencionados en la tabla están en el paquete java.awt.event.

8.3.- MODELO DE EVENTOS BASADO EN DELEGACIÓN Elementos del modelo de Delegación de Eventos

• Fuentes de eventos (event sources)

Son objetos sobre los que se producen eventos y que notifican a los receptores que se han producido esos eventos. Por ejemplo un botón. Las notificaciones son métodos de las listener interface.

• Receptores de eventos (event listener)

Son oyentes (escuchadores) o gestores de eventos. Son objetos instanciados de una clase que implementan un interface específico, denominado listener interface. Hay 11

Page 4: Tutorial08-gesteventos

Laboratorio de Informática II – Gestión de Eventos

8-4

interfaces listener en java.awt.Event: ActionListener, MouseListener, KeyListener, WindowListener,...

Se debe registrar el objeto receptor de eventos con el objeto fuente de eventos, con una línea de código similar a la siguiente:

objetoFuenteEventos.addEventListener(objetoReceptorEventos);

De esta forma, cuando sobre un elemento fuente se produzca un evento, su elemento listener registrado será quien reciba el evento, lo gestione y haga las operaciones correspondientes como respuesta a ese evento.

Los eventos están organizados en jerarquías de clases de eventos, de la siguiente forma:

Cuando ocurre un evento el objeto fuente necesita llamar a su objeto receptor. Entonces, llamará al método apropiado del interface listener correspondiente, y le pasará un objeto que es una instancia de una clase que desciende de EventObject. Los objetos Event encapsulan el evento y contienen información sobre él.

Todo esto ocurre automáticamente una vez que se registra el receptor con la fuente.

8.4.- INTERFACES PARA LA GESTIÓN DE EVENTOS Para facilitar la tarea del programador se han creado una serie de interfaces que deben implementarse cuando se quieren procesar algunos de estos eventos. La siguiente tabla presenta estas interfaces con sus métodos.

Page 5: Tutorial08-gesteventos

Laboratorio de Informática II – Gestión de Eventos

8-5

Interfaz Métodos

ActionListener actionPerformed(ActionEvent)

AdjustmentListener adjustmentValueChanged(AdjustementEvent)

ComponentListener componentHidden(ComponentEvent) componentMoved(ComponentEvent) componentResized(ComponentEvent) componentShown(ComponentEvent)

ContainerListener componentAdded(ContainerEvent) componentRemoved(ContainerEvent)

FocusListener focusGained(FocusEvent) focusLost(FocusEvent)

ItemListener itemStateChanged(ItemEvent)

KeyListener keyPressed(KeyEvent) keyReleased(KeyEvent) keyTyped(KeyEvent)

MouseListener

mouseClicked(MouseEvent) mouseEntered(MouseEvent) mouseExited(MouseEvent) mousePressed(MouseEvent) mouseReleased(MouseEvent)

MouseMotionListener mouseDragged(MouseEvent) mouseMoved(MouseEvent)

TextListener textValueChanged(TextEvent)

WindowListener

windowActivated(WindowEvent) windowClosed(WindowEvent) windowClosing(WindowEvent) windowDeactivated(WindowEvent) windowDeiconified(WindowEvent) windowIconified(WindowEvent)

Page 6: Tutorial08-gesteventos

Laboratorio de Informática II – Gestión de Eventos

8-6

Interfaz Métodos

windowOpened(WindowEvent)

8.5.- ¿CÓMO SE UTILIZAN ESTAS INTERFACES? Supongamos que deseamos que en un Componente que estamos desarrollando (típicamente un Applet, Marco, Diálogo, Ventana o Panel) responda a los eventos generados por el usuario sobre el mismo componente o sobre algunos otros (típicamente contenidos en él). Para ello convertimos a este componente en "escuchador" (Listener) de alugunos de los eventos generados por él o por los otros componentes. Convertir a un componente en escuchador de un tipo de eventos consiste en declarar que implementa la interfaz correspondiente, implementar los métodos de la interfaz y agregarlo a la lista de escuchadores del o de los componentes que originan ese tipo de eventos.

Por ejemplo, si queremos que un Frame responda a los movimientos del ratón sobre él y a los clicks sobre un botón b colocado en el frame, será necesario declarar en su línea definitoria que implementa MouseMotionListener y ActionListener, luego habrá que implementar los métodos de ambas interfaces y también habrá que agregar el frame a la lista de escuchadores de eventos del ratón del propio frame y a la lista de escuchadores de ActionEvent del botón. En otras palabras hay que escribir algo así:

import java.awt.event.*; //Los interfaces están en el paquete java.awt.event import java.awt.Frame; import java.awt.Button; public class MiFrame extends Frame implements MouseMotionListener, ActionListener { //Creación de dos botones Button b1 = new Button("OK"); Button b2 = new Button("Cancel"); //Constructor MiFrame() { /* Se añade un escuchador a la ventana, para los eventos de

movimiento de ratón */ addMouseMotionListener(this); /* Hacemos que los botones respondan al click del ratón, quien

escucha los eventos es la ventana (this) */ b1.addActionListener(this); b2.addActionListener(this); setSize(300,300);

Page 7: Tutorial08-gesteventos

Laboratorio de Informática II – Gestión de Eventos

8-7

} public static void main(String[] args) { MiFrame f = new MiFrame(); f.show(); } /* -- Métodos del interfaz MouseMotionListener --*/ public void mouseDragged(MouseEvent e) { System.out.println("Ratón arrastrado"); } public void mouseMoved(MouseEvent e) { System.out.println("Ratón movido"); } /* -- Métodos del interfaz ActionListener --*/ public void actionPerformed(ActionEvent e) { /* Hay que diferenciar sobre qué botón se ha pinchado, para ello

utilizamos el método getSource del evento */ Button pulsado = (Button)e.getSource(); if (pulsado == b1) System.out.println(“Pulsado OK”); else System.out.println(“Pulsado Cancel”);

} }

Los ejemplos que se presentan a continuación ilustran este procedimiento y muestran cómo extraer información concreta de los eventos para responder a ellos adecuadamente.

8.6.- EJEMPLO: ANALIZANDO EVENTOS Vamos a ver cómo se realizaría un ejercicio donde se necesita analizar los objetos evento. Se creará un interface de usuario con varios botones, cada botón enviará un evento. Se trata, una vez más, de conocer qué botón se ha pulsado (esta vez se usará un procedimiento diferente).

Page 8: Tutorial08-gesteventos

Laboratorio de Informática II – Gestión de Eventos

8-8

Ejemplo: Detección del botón pulsado import java.awt.*; import java.awt.event.*; /* Como la clase implementa el interfaz ActionListener, se convierte en una

clase escuchadora de este tipo de eventos */ public class PruebaBotones extends Frame implements ActionListener { public PruebaBotones() { /* La siguiente sentencia indica cómo se van a colocar los

elementos dentro del frame */ setLayout(new FlowLayout()); //Se crean tres botones Button bAmarillo = new Button("Amarillo"); Button bRojo = new Button("Rojo"); Button bAzul = new Button("Azul"); /* Como queremos que los botones respondan a eventos se les deben añadir "escuchadores" */ bAmarillo.addActionListener(this); //This es la ventana bRojo.addActionListener(this); bAzul.addActionListener(this); //Se añaden los botones al frame add(bAmarillo); add(bRojo); add(bAzul); } /* Al implementar el interface "ActionListener" se deben implementar TODOS sus métodos. En este caso sólo tiene el método

Page 9: Tutorial08-gesteventos

Laboratorio de Informática II – Gestión de Eventos

8-9

"actionPerformed" */ public void actionPerformed(ActionEvent e) { Color color; /* Tomamos la etiqueta del objeto sobre el que se ha producido el

evento, es una alternativa a hacerlo con el método getSource */

String arg = e.getActionCommand(); /* Como hay varios componentes que responden al mismo evento (y

todos tienen el mismo listener), hay que diferenciar sobre cuál se ha producido el evento y actuar en consecuencia */

if (arg.equals("Amarillo")) color = Color.yellow; else if (arg.equals("Rojo")) color = Color.red; else color = Color.blue; setBackground(color); repaint(); } public static void main(String[] args) { Frame f=new PruebaBotones(); f.show(); } }

Hacemos que una clase implemente el interface ActionListener. Este interface se utiliza como un gestor de eventos de propósito general. Se suele utilizar cuando:

• se pulsa un botón.

• se selecciona un elemento de una lista de selección.

• se selecciona un elemento de un menú.

• se pulsa [Enter] en un campo de texto.

Este interface tiene un único método llamado actionPerformed. Este método recibe como parámetro un objeto de la clase ActionEvent, que da información sobre el evento que ha ocurrido accediendo a sus métodos. En nuestro ejemplo hemos utilizado el método getActionCommand de la clase ActionEvent, que devuelve una cadena con el mandato asociado con esta acción. Para botones, concretamente, la cadena contiene la etiqueta del botón.

Se puede utilizar también el método getSource de la clase EventObject para encontrar el componente que produjo el evento. Es decir, devuelve el componente: botón, lista de selección, menú, campo de texto.

Page 10: Tutorial08-gesteventos

Laboratorio de Informática II – Gestión de Eventos

8-10

Otro Ejemplo: Uso una clase escuchadora independiente del interfaz /* Clase escuchadora. Va a actuar cuando el frame reciba algún evento. */ import java.awt.event.*; import java.awt.*; public class miListener implements WindowListener { /* Por implementar el interface WindowListener, hay que implementar todos

los métodos en él declarados. Si no queremos implementarlos porque no nos interesan en nuestra aplicación, los dejamos vacíos.*/

public void windowActivated( WindowEvent e ) { Frame f1=new Frame(); f1.setSize(200,200); f1.show(); } public void windowClosed( WindowEvent e ){} public void windowDeactivated( WindowEvent e ){} public void windowDeiconified( WindowEvent e ){} public void windowIconified( WindowEvent e ){} public void windowOpened( WindowEvent e ){} // Implementamos el método que nos interesa: public void windowClosing( WindowEvent e ) { System.exit( 0 ); } } ---------------------------------------------------------------------------- /* Clase frame. Es la receptora de eventos.*/ import java.awt.*; public class FrameQueSeCierra extends Frame { FrameQueSeCierra() { // Asignamos un tamaño al frame. setSize( 300, 240 ); /* Creamos un objeto listener y lo registramos para que responda a los eventos de este frame*/ addWindowListener( new miListener() ); }

Page 11: Tutorial08-gesteventos

Laboratorio de Informática II – Gestión de Eventos

8-11

} ---------------------------------------------------------------------------- /* Clase que prueba el frame*/ class PruebaFrame { public static void main( String[] p ) { FrameQueSeCierra f = new FrameQueSeCierra(); f.setLocation( 200, 200 ); f.show(); } }

8.7.- ¿CÓMO LO HACE JBUILDER? Veamos cómo gestiona los eventos la herramienta JBuilder:

import java.awt.*; import java.awt.event.*; public class PruebaBotones extends Frame { public PruebaBotones() { //Decidir cómo se muestran los elementos en el frame setLayout(new FlowLayout()); //Se crean tres botones Button bAmarillo=new Button("Amarillo"); Button bRojo=new Button("Rojo"); Button bAzul=new Button("Azul"); /* A cada botón se le añade un "escuchador" particular para que

responda únicamente a los eventos de ese botón */ bAmarillo.addActionListener(new ActionListener() { // Se redefine sólo el método que nos interesa // No hace falta determinar sobre qué objeto se ha

// producido el evento porque este escuchador sólo está // asociado al botón bAmarillo

public void actionPerformed(ActionEvent e) { Color color; String arg=e.getActionCommand(); color = Color.yellow; setBackground(color);

Page 12: Tutorial08-gesteventos

Laboratorio de Informática II – Gestión de Eventos

8-12

} } ); bRojo.addActionListener(new Ac tionListener() { public void actionPerformed(ActionEvent e) { Color color; String arg=e.getActionCommand(); color = Color.red; setBackground(color); } } ); bAzul.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Color color; String arg=e.getActionCommand(); color = Color.blue; setBackground(color); } } ); //Se añaden los botones al frame add(bAmarillo); add(bRojo); add(bAzul); } public static void main(String[] args) { Frame f=new PruebaBotones(); f.show(); } }

8.8.- LAS CLASES EVENTO Como ya se ha comentado, los eventos son objetos Java. Los eventos están organizados en jerarquías de clases de eventos de la siguiente forma:

Page 13: Tutorial08-gesteventos

Laboratorio de Informática II – Gestión de Eventos

8-13

Cuando ocurre un evento sobre un objeto fuente, en función del tipo de acción que genera el evento, se llamara a un método u otro del interface Listener correspondiente y se le pasará como parámetro a este método un objeto que es una instancia de una clase que desciende de AWTObject (cuyo tipo concreto dependerá del tipo de evento que se ha generado) y que proporciona información más específica sobre el evento que se ha producido.

Los objetos descendiente de AWTEvent encapsulan el evento y contienen información sobre él. El tipo de evento determina la clase a la que pertenece el objeto evento generado. Estas clases disponen además de una serie de métodos que permiten consultar información más específica sobre el evento que se ha producido.

A continuación se indican algunos de los métodos más representativos de estas clases. El resto de métodos pueden consultarse en el API en caso de que sea necesario.

METODOS COMUNES A CUALQUIER TIPO DE EVENTO (Clase ObjectEvent)

• getSource()

Devuelve una referencia al objeto sobre el que se ha producido el evento (botón, lista desplegable,...)

METODOS PARA LOS EVENTOS DE SELECCIÓ N PRINCIPAL (Clase ActionEvent)

Entendemos por eventos de selección principal los eventos que se generan cuando se pulsa un botón, cuando se selecciona un elemento de un lista mediante un doble clic, cuando se selecciona un elemento de un menú desplegable o cuando se inserta un texto en un campo de texto y se pulsa ENTER.

Page 14: Tutorial08-gesteventos

Laboratorio de Informática II – Gestión de Eventos

8-14

• getActionCommand()

Devuelve un String dependiente del tipo de objeto sobre el que se haya producido el evento. Generalmente sirve para identificar el objeto sobre el que se ha producido el evento. Para objetos de tipo Button este método devuelve un String que contiene la etiqueta de texto del botón que se ha pulsado.

• getModifiers()

Devuelve un entero que nos permite conocer características adicionales sobre el evento. Por ejemplo, este entero nos permite conocer si en el momento en que se generó el evento las teclas CTRL, ALT o SHIFT estaban pulsadas.

METODOS PARA LOS EVENTOS DEL FOCO DE CONTROL (Clase FocusEvent)

En este grupo incluimos los eventos que se generan, principalmente, como consecuencia de la perdida o ganancia del foco de control por parte de un componente de la interfaz gráfica.

• getOppositeComponent()

Devuelve una referencia al componente gráfico que pierde o gana el foco de control. Ojo, no devuelve la referencia al componente gráfico sobre el que se genera el evento sino al componente gráfico que está al lado del que genera el evento y que pierde o gana el control del foco para dárselo o quitárselo al componente gráfico que ha generado este evento.

METODOS PARA LOS EVENTOS SELECCIÓ N DE ITEMS (Clase ItemEvent)

En este grupo incluimos los eventos que se generan cuando se selecciona un ítem (mediante un simple clic) en, por ejemplo, una lista.

• getItem()

Devuelve una referencia al objeto que representa el ítem seleccionado.

METODOS PARA LOS EVENTOS ASOCIADOS A LAS VENTANAS (Clase WindowEvent)

En este grupo incluimos los eventos que se generan como consecuencia de la manipulación (cierre, apertura, minimización, maximización,...) de las ventanas gráficas.

• getNewState()

Devuelve un entero que indica el nuevo estado de la ventana sobre la que se ha generado el evento.

• getOldState()

Devuelve un entero que indica el estado antiguo de la ventana sobre la que se ha generado el evento.

• getWindow()

Page 15: Tutorial08-gesteventos

Laboratorio de Informática II – Gestión de Eventos

8-15

Devuelve una referencia a la ventana sobre la que se ha generado el evento.

• getOppositeWindow()

Devuelve una referencia a la otra ventana que ha tomado o perdido el foco de control como consecuencia de que la ventana sobre la que se ha generado el evento lo haya perdido o ganado. Por ejemplo, si cerramos una ventana, la ventana cerrada será sobre la que se genera el evento y este método devolverá la referencia a la ventana que ahora toma el foco de control.

METODOS PARA LOS EVENTOS ASOCIADOS AL TECLADO (Clase KeyEvent)

En este grupo incluimos los eventos que se generan como consecuencia de la pulsación de las teclas del teclado.

• getKeyChar()

Devuelve el carácter que se corresponde con la tecla pulsada.

• isShiftDown()

Devuelve un entero que indica si la tecla SHIFT estaba además pulsada cuando se pulsó la otra tecla.

• isAltDown()

Devuelve un entero que indica si la tecla ALT estaba además pulsada cuando se pulsó la otra tecla.

• isControlDown()

Devuelve un entero que indica si la tecla CONTROL estaba además pulsada cuando se pulsó la otra tecla.

METODOS PARA LOS EVENTOS ASOCIADOS AL RATON (Clase MouseEvent)

En este grupo incluimos los eventos que se generan como consecuencia de la manipulación del ratón.

• getClickCounts()

Devuelve un entero con el número de clicks que se han realizado con el ratón.

• getPoint()

Devuelve un objeto de tipo Point que contiene las coordenadas en las que se ha situado el cursor del ratón.

• getX()

La coordenada X en la que está el cursor del ratón.

• getY()

La coordenada Y en la que está el cursor del ratón.

• getModifiers()

Page 16: Tutorial08-gesteventos

Laboratorio de Informática II – Gestión de Eventos

8-16

Devuelve un entero que indica ciertas características especiales del evento. Por ejemplo, nos sirve para identificar qué botón del ratón se ha pulsado.

8.9.- CLASES ADAPTADORAS (ADAPTER CLASSES) Existen una serie de clases llamadas Adapter classes que están definidas para simplificar algunos problema derivados del uso de interfaces. Hay una clase adaptadora por cada uno de los interfaces de listener que implementan todos los métodos con código vacío, de modo que si heredamos de alguna de ellas no necesitaremos más que redefinir los métodos de gestión de eventos que queramos procesar.

Eso sí, tendremos que heredar para que esto sirva para algo porque por sí mismas no hacen nada, lo que muchas veces obligará a crear una segunda clase oyente distinta de la generadora de eventos. Las clases de adaptación son:

• ComponentAdapter

• ContainerAdapter

• FocusAdapter

• KeyAdapter

• MouseAdapter

• MouseMotionAdapter

• WindowAdapter

Ejemplo de Escuchador con clases adaptadoras import java.awt.*; import java.awt.event.*; class Escuchador extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } } class MiFrame extends Frame { public MiFrame() { Escuchador x = new Escuchador(); AddWindowListener(x); } }

Page 17: Tutorial08-gesteventos

Laboratorio de Informática II – Gestión de Eventos

8-17

Ejemplo de Escuchador con interfaces import java.awt.*; import java.awt.event.*; /* Clase que implementa un interfaz Listener, en ese momento se convierte en

una clase escuchadora */ class Escuchador implements WindowListener { /* Se deben implementar TODOS los métodos del interfaz, aunque la

implementación sea vacía */ public void windowClosing(WindowEvent e) { System.exit(0); } public void windowClosed(WindowEvent e){ }

public void windowIconified(WindowEvent e){ } public void windowOpened(WindowEvent e){ } public void windowActivated(WindowEvent e){ } public void windowDeactivated(WindowEvent e){ } public void windowDeiconified(WindowEvent e){ }

} class MiFrame extends Frame { public MiFrame() { Escuchador x = new Escuchador(); addWindowListener(x); /* Es lo mismo que: AddWindowListener(new Escuchador()); */ } }