Post on 27-Jan-2015
transcript
1
IGU en Java:Modelo de Eventos
Ingeniería de la Programación
Práctica 4
2
Contenido
Introducción Elementos del modelo de eventos en Java
Jerarquía de eventos. Fuentes de eventos. Receptores de eventos e interfaces receptoras Registro de receptores. Clases adaptadoras.
Estrategias de programación del receptor.
3
Objetivos
Comprender el modelo de eventos de Java, basado en delegación.
Seleccionar la mejor estrategia para programar los ‘listeners’ de eventos.
Implementar eventos básicos para una IGU.
4
Introducción
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.
Los programas que gestionan las interacciones del usuario de esta forma se dice que están dirigidos por eventos.
5
Introducción
Cada vez que el usuario realiza una determinada acción sobre una aplicación Java (pulsar sobre un botón, pulsar una tecla, pasar el ratón sobre una imagen) se produce un evento que el sistema operativo transmite al entorno de ejecución de Java.
Java crea un objeto de una determinada clase de evento, el cual es transmitido a un determinado método para que lo gestione.
El modelo de eventos de Java está basado en delegación (la responsabilidad de gestionar un evento que ocurre en un objeto – fuente/source- la tiene otro objeto-receptor/listener-).
Objeto oyenteObjeto fuente
1. Se registra como oyente
2. Lo apunta en la lista de oyentes
3. Cuando se produce un evento se comunica a todos los oyentes, mediante la invocación de un método del oyente (al que se le pasa como parámetro el evento)
6
Introducción
Cada componente de la interfaz de usuario puede generar varios tipos de eventos.
Java permite varios receptores para un mismo tipo de evento de un emisor.
De igual forma varios emisores se pueden asociar a un único receptor.
Objeto fuente
Objeto oyente 1
Objeto oyente 2
Objeto fuente 1
Objeto fuente 2
Objeto oyente
7
Introducción
public void actionPerformed(
java.awt.event.ActionEvent e)
{
// código de manejo del evento
}
JTextField object
manejadortextField1
listenerList
Esta referencia la crea la sentencia:
textField1.addActionListener( manejador);
8
Elementos del modelo de eventos de Java
Jerarquías de clases de Eventos Fuentes de Eventos (event sources) Receptores de Eventos (event listener) Interfaces listener. Registrar eventos. Adaptadores (adapter classes)
9
Jerarquías de eventos
Cada vez que se produce un evento dicho evento se representa como una instancia de una clase descendiente de AWTEvent.
ActionEvent (1)
TextEvent (1)
AWTEvent
Object
EventObject
AdjustmentEvent (1)
ComponentEvent ItemEvent (1)
FocusEvent WindowEventInputEventContainerEvent PaintEvent
KeyEvent MouseEvent
10
Fuentes de eventos
La fuente (source) de un evento es el objeto que lo detecta y lo comunica al objeto receptor (listener).
Ejemplos de fuentes y eventos generados
Fuente Evento generado
Pulsación sobre un botónPulsa <Return> sobre un campo de textoPulsar sobre una opción de menú
ActionEvent
Cerrar la ventana principal de la aplicación WindowEvent
Pulsar con el ratón sobre un componente MouseEvent
Mover el ratón sobre un componente MouseEvent
Un componente se hace visible ComponentEvent
11
Eventos generados por componentes AWT
Componente Evento Significado
Button ActionEvent Pulsar el ratón sobre un botón
Checkbox ItemEvent Seleccionar o deseleccionar un item
CheckboxMenuItem ItemEvent
Choice ItemEvent
Component FocusEvent Obtener o perder el foco
ComponentEvent Mover, cambiar tamaño, mostrar u ocultar un componente
KeyEvent Pulsar o soltar un tecla
MouseEvent
Pulsar o soltar un botón del ratón, entrar o salir de un componente, mover o arrastrar el ratón (tenga en cuenta que el evento tiene 2 interfaces oyentes MouseListener y MouseMotionListener)
Container ContainerEvent Añadir o eliminar un componente de un contenedor
List ActionEvent Hacer doble click sobre un item de la lista
ItemEvent Seleccionar o deseleccionar un item de la lista
MenuItem ActionEvent Seleccionar un item de un menú
Scrollbar AdjustmentEvent Cambiar el valor de la barra de desplazamiento
TextComponent TextEvent Cambiar el contenido (texto).
TextField ActionEvent Pulsar intro al editar un texto
Window WindowEvent Acciones sobre una ventana: abrir, cerrar, iconizar (minimizar), restablecer, cerrar.
12
Eventos generados por componentes AWT (2)
Hay componentes de AWT que no poseen eventos propios (TextArea), pero todos los eventos de una superclase (en la jerarquía AWT) se aplican a la subclase.
Con la consideración anterior un TextArea puede generar los siguientes eventos (todos heredados):
Componente Evento
TextArea ComponentEvent
FocusEvent
KeyEvent
MouseEvent
TextEvent
13
Receptores de eventos
Cuando ocurre un evento un objeto fuente puede llamar a uno o varios objetos receptores.
Los receptores (listeners) de eventos son objetos de una clase determinada que implementa un interface específico llamado interface listener.
Existe una interface listener por cada tipo de evento.
14
Eventos generados por componentes Swing
Los eventos generados por los componentes Swing son de dos tipos:
Una primera clase que engloba los oyentes que todos los componentes Swing pueden soportar:
Component Listener: Oyentes para el cambio en el tamaño, posición o visibilidad de un componente.
Focus Listener: Oyentes para manejar la perdida o ganancia de foco del teclado.
Key Listener: Oyentes para detectar pulsaciones de teclado; los eventos de teclado son activados únicamente por el componente que tiene el foco del teclado.
Mouse Listener: Oyentes para “clicks” del ratón, pulsar un botón del ratón, soltar un botón del ratón, entrar en el área de dibujo del componente, salir de la misma.
Mouse-motion Listener: Cambiar la posición del cursor del ratón sobre un componente.
Mouse-wheel Listener: Movimiento de la rueda del ratón sobre un componente.
Hierarchy Listener: Oyentes para los cambios en la jerarquía de un componente.
Hierarchy Bounds Listener: Oyentes para el cambio de posición y de tamaño.
Una segunda clase que engloba oyentes específicos para cada tipo de componente.
15
Oyentes específicos
16
Oyentes específicos (2)Oyente Componente
action caret change document, undoable edit
item list selection
window other
password field
popup menu Popup menu
progress bar radio button slider spinner tabbed pane table table model
table column table model, cell
editor
text area text field text pane hyperlink
toggle button tree tree expansion
tree will expand tree model
tree selection
17
Interfaces receptoras
Evento Interfaz Listener Métodos de la Interfaz
ActionEvent ActionListener actionPerformed
AdjustmentEvent AdjustmentListener adjustmentValueChanged
ComponentEvent ComponentListener componentHidden, componentMoved, componentResized, componentShown
ContainerEvent ContainerListener componentAdded,componentRemoved
FocusEvent FocusListener focusGained, focusLost
ItemEvent ItemListener itemStateChanged
KeyEvent KeyListener keyPressed,keyReleased,keyTyped
MouseEvent MouseListener mousePressed,mouseReleased, mouseEntered, mouseExited.
MouseMotionListener mouseDragged, mouseMove
TextEvent TextListener textValueChanged
WindowEvent WindowListener windowActivated, windowClosed, windowClosing,windowDeactivated, windowDeiconified, windowIconified, windowOpened.
18
Registro del receptor
Cuando ya disponemos del objeto fuente y del objeto receptor es necesario asociarlos, es decir, hay que registrar el objeto receptor de eventos con el objeto fuente de los mismos:
El objeto receptor debe implementar una determinada interface listener. Los métodos de la interfaz serán llamados cuando se produzca el evento.
Con la instrucción remove<Evento>Listener(ObjetoReceptor) se puede eliminar el objeto oyente.
ObjetoFuenteEventos.add<Event>Listener(ObjetoReceptorEventos)
Se cambia por el evento que se quiera recibir
19
Adaptadores
Los adaptadores (adapters class) simplifican la programación de las clases receptoras ya que no es necesario implementar todos los métodos de las interfaces listeners.
Existe una clase adaptadora (xxxAdapter) por cada interface (xxxListener) que contenga más de un método: MouseAdapter, WindowAdapter, KeyAdapter, MouseMotionAdapter, FocusAdapter, ContainerAdapter y ComponentAdapter, etc.
Las clases adaptadoras implementan (mediante código vacío) todos los métodos de la correspondiente interfaz.
Las adaptadoras se extienden y se incluyen los métodos de la interfaz que sean de interés.
20
Programación del receptor: alternativas
Se pueden utilizar tres estrategias:
1. Crear el receptor como clase interna, donde una clase interna es una clase definida dentro de otra, pudiendo acceder a todos los métodos y atributos de la clase que la contiene.
2. Crear el receptor como una clase independiente.
3. La propia ventana implemente el receptor.
21
1. Receptor: clase interna
Ejemplo: Cambiar el color de fondo de un formulario al pulsar un botón: gris-> blanco -> gris (proyecto visual editor ejemplo1)
El emisor es un JButton y el evento generado es del tipo ActionEvent. El receptor debe implementar a la interface ActionListener que tiene
únicamente el método: void actionPerformed( ActionEvent e)
Dos soluciones: 1.a clase interna programada manualmente. (ejemplo 1) 1.b clase anónima interna, es lo que genera visual editor. (ejemplo 2)
22
1. Receptor: clase interna
public class VentanaPrincipal extends JFrame {
private static final long serialVersionUID = 1L;private JPanel jContentPane = null;private JButton Boton = null;
/* código añadido */ private boolean colorgris = true; … /* código inicialización del componente */
private void initialize() {this.setSize(300, 200);this.setContentPane(getJContentPane());this.setTitle("Ejemplo 1");ProcesaBoton pb = new ProcesaBoton(); this.Boton.addActionListener(pb);}…//* receptor clase local class ProcesaBoton implements ActionListener { public void actionPerformed(ActionEvent e) { if (colorgris) jContentPane.setBackground(Color.white); else jContentPane.setBackground(Color.lightGray); colorgris = !colorgris; } }
}
23
1. Receptor código generado por eclipse
Eclipse genera una clase anónima interna, vea ejemplo 2.
private JButton getBoton() {if (Boton == null) {Boton = new JButton();Boton.setText("Cambiar color");Boton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { // TODO Auto-generated Event stub actionPerformed() if (colorgris) jContentPane.setBackground(Color.white); else jContentPane.setBackground(Color.lightGray); colorgris = ! colorgris; } }); }return Boton;}
Clase anónima interna
24
2. Receptor: clase separada
Al ser clases separadas no se puede acceder a las características de la clase que contiene al emisor, si éstas se quieren modificar se pasa una referencia a la ventana de la aplicación, en la llamada al constructor del receptor (ejemplo 3).
public class Ejemplo3 extends JFrame {
// el receptor se registra igual en el caso 1.private void initialize() { this.setSize(300, 200);
this.setContentPane(getJContentPane()); this.setTitle("Ejemplo 3");
// registrar el receptor...
ProcesaBoton pb = new ProcesaBoton(this);
this.Boton.addActionListener(pb); }
public void CambiarColor() { }
}
class ProcesaBoton implements ActionListener {
private Ejemplo3 Marco;
public ProcesaBoton(Ejemplo3 MarcoPrincipal)
{ Marco = MarcoPrincipal;}
public void actionPerformed(ActionEvent e)
{ Marco.CambiarColor();}
}
25
2. Receptor: clase separada pero generada automáticamente
Algunas herramientas como JBuilder o JDeveloper generan el siguiente código.
public class Ejemplo4_Marco extends JFrame { JPanel contentPane; JButton Boton = new JButton(); public Ejemplo4_Marco() {… }
private void jbInit() throws Exception { contentPane = (JPanel) getContentPane(); contentPane.setLayout(boxLayout21); setSize(new Dimension(400, 300)); setTitle("Ejemplo 4"); Boton.setText("Cambiar Color"); Boton.addActionListener( new Ejemplo4_Marco_Boton_actionAdapter(this)); contentPane.add(Boton, null); } public void Boton_actionPerformed(ActionEvent e) {
}}
26
2. Receptor: clase separada pero generada automáticamente
La solución es similar a la del ejemplo 3
class Ejemplo4_Marco_Boton_actionAdapter implements ActionListener {
private Ejemplo4_Marco adaptee;
public Ejemplo4_Marco_Boton_actionAdapter(Ejemplo4_Marco adaptee)
{ this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.Boton_actionPerformed(e);
}
}
27
3. Receptores: la ventana implementa el receptor
public class Ejemplo5 extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
private JPanel jContentPane = null;
private JButton Boton = null;
private boolean colorgris = true;
… // en azul código añadido a mano.
private JButton getBoton() {
if (Boton == null) {
Boton = new JButton();
Boton.setText("Pulsa");
Boton.setBounds(new Rectangle(16, 46, 66, 26));
Boton.addActionListener(this);}
return Boton; }
…
public void actionPerformed(ActionEvent e) {
if (colorgris) jContentPane.setBackground(Color.white);
else jContentPane.setBackground(Color.lightGray);
colorgris = ! colorgris;
}
…
}
28
Ejemplo clases adaptadoras
Ejemplo: validar la longitud de un campo de texto (JTextField) cuando pierde el foco (FocusEvent)*.
El receptor tiene que ser un objeto que implemente a la interface FocusListener que tiene los métodos:
public void focusLost( FocusEvent e)public void focusGained( FocusEvent e)
Utilizaremos el adaptador FocusAdapter, ya que únicamente queremos implementar el método focusLost.
El receptor será una clase separada.
*Lo habitual es programar un manejador para los botones
class ManejaFocoDNI extends java.awt.event.FocusAdapter{ private Ejemplo6 adaptador; public ManejaFocoDNI(Ejemplo6 adaptador1) { this.adaptador = adaptador1; } public void FocusLost(FocusEvent e) { // código para manejar la pérdida de foco. System.out.println("Perdida de foco"); }}
29
this.addWindowListener(new java.awt.event.WindowAdapter() {public void windowClosing(java.awt.event.WindowEvent e) {
if (jtfText.getText().compareTo("")==0) ;else {
int resp;resp=javax.swing.JOptionPane.showConfirmDialog(null, “¿Estas seguro?", "Aviso",
javax.swing.JOptionPane.OK_CANCEL_OPTION);if (resp==JOptionPane.OK_OPTION)
System.exit(0);
}}
});}
Otro ejemplo: cerrar una ventana
30
Referencias
Tutorial sobre Swing, accesible en: http://www.programacion.com/java/tutorial/swing/ Tutorial sobre Java, con eventos.
http://www.itapizaco.edu.mx/paginas/JavaTut/froufe/introduccion/indice.html
Creating a GUI with JFC/Swing, accesible en:http://java.sun.com/docs/books/tutorial/uiswing/TOC.html
31
Ejercicio
Consiste en implementar la funcionalidad de la Gestión de Máquinas de la práctica 3, haciendo uso de la clase ModeloTablaMaquina.
Para ello debemos implementar los manejadores de eventos de los diferentes botones y opciones de menú, haciendo que ejecuten los métodos del objeto ModeloTablaMaquina asociado en la Práctica 3 a la tabla de la Ventana Principal.
32
Ejercicio
Punto 1: Enlace entre ventanas. Botones Añadir y Detalle.
Debe pasarle como parámetro el modelo de la tabla
Debe pasarle como parámetro la máquina seleccionada
VentanaDetalle v=new VentanaDetalle(tabla.getModel());v.setVisible(true);
Maquina m= modelo.recuperaMaquinaPorPosicion (tabla.getSelectedRow());
VentanaDetalle v=new VentanaDetalle(m);v.setVisible(true);
33
Ejercicio Punto 2: Constructor y Botones Ventana Detalle.
Constructor: Sobrecargado. Recibe un ModeloTablaMaquina o una Maquina. En el caso de recibir una Maquina visualiza sus datos en la caja de texto y deshabilita el botón Guardar.
Botón Guardar. Habilitado sólo cuando el constructor recibe un ModeloTablaMaquina (i.e. se accede con el botón Añadir de la Ventana Principal). Crea una Máquina a partir de los campos de texto y la guarda mediante el método addMaquina del la clase ModeloTablaMaquina. Si todo es correcto cierra la Ventana Detalle.
Botón Volver: Cierra la Ventana Detalle
34
Ejercicio Punto 3: Menús de la Ventana Principal.
Menu Archivo Guardar: serializa el listado de máquina mediante el método guardaMaquinas de la clase ModeloTablaMaquina. Utilice el cuadro de diálogo implementado en la clase JFileChooser para permitir al usuario escoger el fichero que almacena los objetos la primera vez que se guarda. En veces sucesivas usar el fichero seleccionado sin consultar al usuario.
Guardar como: serializa el listado de máquinas mediante el método guardaMaquinas de la clase ModeloTablaMaquina. Utilice el cuadro de diálogo implementado en la clase JFileChooser para permitir escoger siempre el fichero que almacena los objetos.
Cargar de disco: carga el listado de máquina desde disco mediante el método cargaMaquinas de la clase ModeloTablaMaquina. Utilice el cuadro de diálogo implementado en la clase JFileChooser para seleccionar siempre el fichero desde donde cargar.
Salir: Cierra la aplicación
Menú Aspecto: Cambia los colores de la fuente y el fondo de la aplicación. Utilice la paleta de colores implementada en la clase JColorChooser.
35
Ejercicio Punto 4: Barra de Herramientas y Botón Borrar de la Ventana
Principal. Barra de Herramientas: sus botones guardan y cargan en
disco como los items “Guardar como” y “Cargar de disco” del menú archivo.
Botón Borrar: Elimina la Maquina seleccionada usando el método borraMaquinaPorPosicion de la clase ModeloTablaMaquina.
36
Ejercicio
Adicionalmente: Utilice la barra de estado para informar al usuario de las acciones realizadas.Antes de borrar una Máquina pregunte al usuario si está seguro. Gestione las siguientes excepciones. En cada una de ellas debe informarse al usuario con un mensaje de error en una caja de diálogo (puede utilizar la clase JOptionPane)a)Si se intenta añadir una Máquina con alguno de sus campos en blanco, se avisará al usuario con un mensaje.b)Si ya existe una Máquina con ese número, se avisará al usuario con un mensaje. Igual que en la Práctica 2.c)Cuando se cierra la aplicación (desde el aspa del marco o desde la opción de menú Salir) se deberá detectar si ha habido cambios en la lista de Máquinas desde el último guardado, informando al usuario si desea almacenar en disco dichos cambios. Si es la primera vez que se almacena la lista se pedirá al usuario el nombre del fichero (como en la opción de menú Guardar como…)