Está en la página 1de 29

Tópicos Avanzados de Programación

Apuntes de la Unidad 1

MTI. Rosa Villegas Paz

1. Interfaz Gráfica de usuario

1.1. Creación de interfaz gráfica para usuarios.

La interfaz es la parte visible de las aplicaciones, siendo lo que se percibe de


las mismas; por ello, cada vez se les está dando una importancia mayor y se
está poniendo más cuidado en su desarrollo. La creación de interfaces de
usuario es un área, dentro del desarrollo de software, que ha evolucionado
mucho en los últimos años y lo sigue haciendo a día de hoy.

La usabilidad es una medida de uso de un producto por determinados


usuarios, con el fin de alcanzar ciertos objetivos de eficiencia, efectividad y
satisfacción, todo ello dentro de un contexto de uso concreto.

Por lo tanto, la interfaz de usuario debe ser usable, lo que implicará que el
usuario consiga realizar las tareas por medio de ella de forma rápida y sencilla,
y se encuentre cómodo con la aplicación.

Una interfaz gráfica de usuario (GUI) es una interfaz de usuario en la que se


hace uso de un entorno gráfico. Es decir, permite la interacción del usuario con
el ordenador mediante la utilización de imágenes, objetos pictóricos (ventanas,
iconos, botones, etcétera), además de texto. GUI es un acrónimo del vocablo
inglés Graphical User Interface.

Una aplicación sin un interfaz fácil, impide que los usuarios saquen el máximo
rendimiento del programa. Java proporciona los elementos básicos para
construir decentes interfaces de usuario a través del AWT, y opciones para
mejorarlas mediante Swing, que sí permite la creación de interfaces de usuario
de gran impacto y sin demasiados quebraderos de cabeza por parte del
programador.

AWT y Swing
Java provee dos APIs con las que podemos trabajar para desarrollar GUIs. La
más básica es AWT (Abstract Window Toolkit). Para ser sincero, la API de
AWT es muy limitada y no provee componentes fundamentales como árboles,
grillas y solapas (entre otras limitaciones). Generalmente, las interfaces
gráficas se desarrollan con Swing. Cabe aclarar que todas las clases de Swing
heredan de clases de AWT.

Las clases de Swing (en general) son fácilmente identificables porque


comienzan con el prefijo “J”. Por ejemplo: JButton, JTextField, JTextArea,
JPanel y JFrame son clases de Swing.

Las interfaces gráficas están formadas por ventanas de diferentes tipos que se
pueden solapar, mover, cerrar, etc. Dentro de estas ventanas se encuentran
otros elementos (botones, etiquetas, campos de texto, imágenes, etc.) que
permiten introducir datos y mostrar el estado de la aplicación. El ratón y el
teclado permiten manejar los elementos que forman parte de la interfaz.

Para implementar una aplicación que nos permita generar una interfaz gráfica
de usuario se debe de seguir la siguiente estructura:

Figura 1. Estructura de GUI

Componentes y Contenedores
A todos los elementos gráficos que tenemos a disposición para crear GUIs, los
llamamos “componentes” simplemente porque todos son objetos de clases que
heredan de la clase base Component. Algunos ejemplos son Button, List,
TextField, TextArea, Label, etcétera.

En una GUI los componentes son contenidos en “contenedores” o containers.


Un container es un objeto cuya clase hereda de Container (clase que a su vez
es subclase de Component) y tiene la responsabilidad de contener
componentes.

Para orientarnos mejor analizaremos un extracto de la rama Component del


árbol de clases que provee Java.
En este árbol vemos que todas las clases heredan de Component quien, a su
vez, hereda de Object. Las clases Panel, Window y Frame además son
containers porque heredan de Container.

Generalmente, una GUI se monta sobre un Frame. Este será el container


principal que contendrá los componentes de la interfaz gráfica. Notemos que
como los containers también son componentes entonces un container podría
contener a otros containers.

Los componentes son clases de objetos que permiten utilizar elementos


gráficos para crear interfaces gráficas y están divididos en dos grandes grupos:
los contenedores y los componentes. Un componente, también denominado
componente simple o atómico, es un objeto que tiene una representación
gráfica, que se puede mostrar en la pantalla y con la que puede interactuar el
usuario. Ejemplos de componentes son los botones, campos de texto,
etiquetas, casillas de verificación, menús, etc.

Algunos de estos componentes del paquete AWT y del SWING están


resumidos en la siguiente tabla:
Contenedores.
Un contenedor es un componente al que se le incluirán uno o más
componentes o contenedores. Los contenedores permiten generar la
estructura de una ventana y el espacio donde se muestra el resto de los
componentes contenidos. En ella y que conforman la interfaz de usuario. Los
contenedores de alto nivel más utilizados se muestran en la siguiente tabla

Jerarquía y tipos de los componentes gráficos.


Las clases gráficas se presentan organizadas en los siguientes grandes
grupos:
● Clases básicas.
● Contenedores de alto nivel.
● Contenedores intermedios.
● Componentes atómicos.

Clases básicas.
Proporcionan el soporte y funcionalidad básica para el resto de los
componentes. La raíz de todos los elementos gráficos en Java es la clase
abstracta java.awt.Component y su subclase abstracta java.awt.Container. La
clase javax.swing.JComponent, es una subclase de java.awt.Container y que
es la clase base para prácticamente todos los componentes SWING.

Los Frames

Se emplea para crear una ventana principal de una aplicación. Esta ventana
posee un marco que incluye los controles de minimizar, restaurar/maximizar y
cerrar. A este contenedor se le puede agregar una barra de menús
( javax.swing.JMenuBar ). Los componentes gráficos no se añaden
directamente al JFrame sino a su panel de contenido. También el
administrador de diseño ( Layout ) se le debe aplicar a este panel de contenido.
Los métodos mas frecuentemente utilizados en un JFrame son:

f.setSize(420,450); // tamaño de la ventana


f.setLocation(50,50); // posición de la esquina superior izquierda de la ventana
f.getContentPane().setLayout(objetoLayout); // establece el administrador de diseño
f.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);//
cerrar ventana
f.setTitle("Operadores de Java"); // pone texto en el título de la ventana
f.setJMenuBar(barraDeMenu); // agrega una barra de menú a la ventana
f.setVisible( true ); // hace visible o invisible la ventana
f.pack(); // asigna tamaño iniciales a los componentes
f.getContentPane().add(componente); // añade un componente a la ventana
f.addXXXXXListener(objetoListener ); // añade un oyente de eventos

JDialog
La clase javax.swing.JDialog es la clase raíz de las ventanas secundarias
que
implementan cuadros de diálogo en SWING. Estas ventanas dependen de una
ventana principal (o con marco, normalmente de la clase JFrame ) y si la
ventana principal se cierra, se iconiza o desiconiza, las ventanas secundarias
realizan la misma operación de forma automática. Estas ventanas pueden ser
modales o no modales, es decir, limitan la interacción con la ventana principal
si así se desea. El constructor más frecuentemente utilizado es:

// crea un Jdialog con la ventana de la que depende, un título y si es modal o no.


JDialog dialogo = new JDialog( frame, “Titulo del Jdialog”, true );

La clase JDialog puede utilizar todos los métodos descritos para la clase
JFrame.

Cuadros de diálogo estándar con la clase javax.swing.JOptionPane.


Esta clase se utiliza para crear los tipos de cuadros de diálogo más habituales,
como los que permiten pedir un valor, mostrar un mensaje de error o
advertencia, solicitar una confirmación, etc. Todos los cuadros de diálogo que
implementa JOptionPane son modales (esto es, boquean la interacción del
usuario con otras ventanas). La forma habitual de uso de la clase es mediante
la invocación de alguno de sus métodos estáticos para crear cuadros de
diálogo. Tienen el formato show<Tipocuadro>Dialog, donde el tipo puede
ser:

Message para informar al usuario con un mensaje, vea figura siguiente

//cuadro de mensaje
JOptionPane.showMessageDialog(ventana,
"No se ha podido conectar a la base de datos", //mensaje
"Error en conexión", // título
JOptionPane.ERROR_MESSAGE); // icono

Confirm para solicitar una confirmación al usuario con las posibles respuestas
de si, no o cancelar, ver figura siguiente:
// cuadro de confirmación. Devuelve YES_OPTION , NO_OPTION

int confirma = JOptionPane.showConfirmDialog(ventana,


"¿Desea cerrar el cuadro de Selección de archivos", //mensaje
"Confirmar cerrar", // título
JOptionPane.YES_NO_CANCEL_OPTION, //botones
JOptionPane.INFORMATION_MESSAGE); // icono

if( confirma == JOptionPane.YES_OPTION ) // se compara confirmación


System.exit( 0 );

Input para solicitar la entrada de un dato, ver figura siguiente:


//cuadro de entrada. Devuelve la cadena introducida o null si se cancela
String cadena = JOptionPane.showInputDialog(ventana,
"Dar N = ", // mensaje
"Solicitud de un número", //título
JOptionPane.QUESTION_MESSAGE); // icono
int n = Integer.parseInt(cadena); // conversión de cadena a entero

Option permite crear una ventana personalizada de cualquiera de los tipos


anteriores, ver figura siguiente:
//Cuadro de opción personalizado, devuelve en n el botón pulsado
String[] perrosFamosos = { "Snoopy","Super Can","Fido","Patan","Tribilín",
"Scoobe Doo","Pluto","Rintintín","Lasie" };

int n = JOptionPane.showOptionDialog(null,
"¿Cuál es su perro favorito?", //mensaje
"Mensaje de confirmación", //título
JOptionPane.YES_NO_CANCEL_OPTION, // botones
JOptionPane.QUESTION_MESSAGE,
null, // utiliza icono predeterminado
perrosFamosos,
perrosFamosos[0]); // botón determinado
System.out.println( "Mi perro favorito es: " + perrosFamosos[n] );

Distribución de componentes (layouts)


Los containers contienen componentes y estos son acomodados dentro del
espacio visual del container respetando una determinada distribución que
llamaremos layout.

El layout puede ser absoluto o relativo. En general, utilizamos layouts


absolutos cuando trabajamos con herramientas visuales en las que podemos
dibujar la GUI. En cambio, los layouts relativos definen reglas y los
componentes se acomodan automáticamente dentro del container en función
de las reglas que impone el layout.

Trabajar con layouts relativos es mucho más difícil que hacerlo con layouts
absolutos. Sin embargo, los layouts relativos proveen dos importantes ventajas
sobre los absolutos:
1. Como los componentes se ajustan de forma automática dentro del
container, cualquier cambio en el
tamaño de la ventana no impacta
visualmente en su distribución ya que se
reacomodarán y mantendrán
proporcionalmente el diseño original.

2. Java es un lenguaje multiplataforma y


cada plataforma puede tener su propio
estilo de componentes gráfcos. Esto es
lo que se llama look and feel. Trabajar
con layouts relativos nos asegura que
una GUI que se ve bien en Windows
también se verá bien en Linux y en
Mac porque, por más que el look and feel sea diferente en cada plataforma,
los componentes se reacomodarán para respetar siempre las proporciones
del diseño original.

Estudiaremos los siguientes 3 layouts:


 FlowLayout – Distribuye los componentes uno al lado del otro en la parte
superior del container. Por defecto provee una alineación centrada, pero
también puede alinearlos hacia la izquierda o hacia la derecha.
 BorderLayout – Divide el espacio del container en 5 regiones: NORTH,
SOUTH, EAST, WEST y CENTER (norte, sur, este, oeste y centro). Admite
un único componente por región.
 GridLayout – Divide el espacio del container en una grilla de n flas por m
columnas donde todas las celdas son de igual tamaño. Admite exactamente
n por m componentes, uno por celda.
 GridBagLayout – Divide el espacio del container en una grilla donde cada
componente puede ocupar varias flas y columnas. Además, permite
distribuir el espacio interno de cada celda. Este layout es realmente
complejo y su análisis excede los objetivos de este capítulo.

FlowLayout
Comenzaremos analizando el código de una interfaz gráfica que utiliza un
FlowLayout para mantener tres botones centrados en la parte superior de la
ventana.
package unidad_1;

import java.awt.*;

public class Ventana extends Frame{


//definir los objetos
private Button b1,b2,b3;
public Ventana(){
//el consturctor padre recibe el titulo de la ventana
super("Mi primer ventana");

//definimos la distribucion de componentes


setLayout(new FlowLayout());

//instanciar los objetos y agregalos al contenedor


(container)
b1=new Button("Boton 1");
add(b1);

b2 = new Button("Boton 2");


add(b2);

b3 = new Button("Boton 3");


add(b3);

//definir tamaño a la ventana y hacerla visible


setSize(300,300);
setVisible(true);
}

public static void main(String[] args) {


Ventana v=new Ventana();
}

Si queremos una alineación a la izquierda

BorderLayout
Este layout divide el espacio del container en cinco regiones o cuatro bordes y una
región central. Admite solo un componente por región, por lo tanto, un container
con esta distribución solo podrá contener a lo sumo cinco componentes.
package unidad_1;
import java.awt.*;

public class Ventana2 extends Frame{

private Button bNorth, bSouth, bWest, bEast, bCenter;

public Ventana2() {
super("Esta es la Ventana 2");
setLayout(new BorderLayout());
bNorth = new Button("Norte");
add(bNorth, BorderLayout.NORTH);
bSouth = new Button("Sur");
add(bSouth, BorderLayout.SOUTH);
bWest = new Button("Oeste");
add(bWest, BorderLayout.WEST);
bEast = new Button("Este");
add(bEast, BorderLayout.EAST);
bCenter = new Button("Centro");
add(bCenter, BorderLayout.CENTER);
setSize(300, 300);
setVisible(true);
}
public static void main(String[] args) {
Ventana2 v2 = new Ventana2();
}
}

GridLayout
Para finalizar estudiaremos el GridLayout que divide el espacio del container en
una grilla de n flas por m columnas donde todas las celdas tienen exactamente la
misma dimensión.
package unidad_1;
import java.awt.*;
public class Ventana3 extends Frame {
private Button b1, b2, b3, b4, b5, b6, b7, b8, b9;

public Ventana3() {
super("Esta es la Ventana 3");
setLayout(new GridLayout(3, 3));
b1 = new Button("Boton 1");
add(b1);
b2 = new Button("Boton 2");
add(b2);
b3 = new Button("Boton 3");
add(b3);
b4 = new Button("Boton 4");
add(b4);
b5 = new Button("Boton 5");
add(b5);
b6 = new Button("Boton 6");
add(b6);
b7 = new Button("Boton 7");
add(b7);
b8 = new Button("Boton 8");
add(b8);
b9 = new Button("Boton 9");
add(b9);
setSize(300, 300);
setVisible(true);
}

public static void main(String[] args) {


Ventana3 v3 = new Ventana3();
}
}

Combinación de layouts
Los layouts que analizamos hasta aquí son en sí mismos muy limitados y no
tienen la flexibilidad suficiente que nos permita pensar en diseñar una interfaz
gráfica que pueda resultar verdaderamente funcional. Sin embargo, si pensamos
que una GUI puede construirse en base a combinaciones de estos layouts
entonces la cosa puede ser diferente.
Comenzaremos por un caso simple: una calculadora.
Esta interfaz gráfica se logra utilizando un BorderLayout que en el norte tiene una
instancia de TextField (el display) y en el centro tiene un Panel (otro container) con
un GridLayout de 4 flas por 4 columnas con un Button en cada celda.
package unidad_1;
import java.awt.*;
public class Calculadora extends Frame {

private Button b0, b1, b2, b3, b4, b5, b6, b7, b8, b9;
private Button bDec, bMas, bMenos, bPor, bDiv, bIgual, bBorrar;
private TextField tfDisplay;

public Calculadora() {
super();
setLayout(new BorderLayout());
// en el NORTE ubico el display
tfDisplay = new TextField();
add(tfDisplay, BorderLayout.NORTH);
// en el CENTRO ubico el teclado
Panel pTeclado = _crearTeclado();
add(pTeclado, BorderLayout.CENTER);
// este metodo dimensiona y setea el tamanio exacto
// necesario para contener todos los componentes del Frame
pack();
setVisible(true);
}

private Panel _crearTeclado() {


// instancio los 16 botones
b0 = new Button("0");
b1 = new Button("1");
b2 = new Button("2");
b3 = new Button("3");
b4 = new Button("4");
b5 = new Button("5");
b6 = new Button("6");
b7 = new Button("7");
b8 = new Button("8");
b9 = new Button("9");
bDec = new Button(".");
bMas = new Button("+");
bMenos = new Button("-");
bPor = new Button("*");
bDiv = new Button("/");
bIgual = new Button("=");
// instancio un Panel (un container) con GridLayout de 4 x 4
Panel p = new Panel(new GridLayout(4, 4));
// Agrego los botones al panel
// fila 0 (la mas de mas arriba)
p.add(b7);
p.add(b8);
p.add(b9);
p.add(bDiv);
// fila 1 (la segunda comenzando desde arriba)
p.add(b4);
p.add(b5);
p.add(b6);
p.add(bPor);
// fila 2 (la tercera comenzando desde arriba)
p.add(b1);
p.add(b2);
p.add(b3);
p.add(bMenos);
// fila 3 (la cuarta comenzando desde arriba)
p.add(bDec);
p.add(b0);
p.add(bIgual);
p.add(bMas);
// retorno el Panel con todos los botones agregados
return p;
}

public static void main(String[] args) {


Calculadora c = new Calculadora();
}
}

Pasemos ahora a un ejemplo con mayor complejidad: una ventana de chat, para
comprender su diseño podemos verla dividida de la siguiente manera:

package unidad_1;
import java.awt.*;

public class chat extends Frame {

private TextField tfNick;


private TextField tfMensaje;
private Button bLogin;
private Button bLogout;
private Button bEnviar;
private List lstLog;

public chat() {
super("Chat");
setLayout(new BorderLayout());
// panel norte
Panel pNorth = _crearPNorte();
add(pNorth, BorderLayout.NORTH);
// panel central
Panel pCenter = _crearPCenter();
add(pCenter, BorderLayout.CENTER);
// panel sur
Panel pSouth = _crearPSur();
add(pSouth, BorderLayout.SOUTH);
setSize(400, 300);
setVisible(true);
}

private Panel _crearPNorte() {


Panel p = new Panel(new FlowLayout(FlowLayout.LEFT));
p.add(new Label("Nick:"));
tfNick = new TextField(10);
p.add(tfNick);
bLogin = new Button("Login");
p.add(bLogin);
bLogout = new Button("Logout");
p.add(bLogout);
return p;
}

private Panel _crearPCenter() {


Panel p = new Panel(new BorderLayout());
// norte
p.add(new Label("Conversacion:"), BorderLayout.NORTH);
// centro
lstLog = new List();
p.add(lstLog, BorderLayout.CENTER);
return p;
}

private Panel _crearPSur() {


Panel p = new Panel(new BorderLayout());
// oeste
p.add(new Label("Mensaje:"), BorderLayout.WEST);
// centro
tfMensaje = new TextField();
p.add(tfMensaje, BorderLayout.CENTER);
// este
bEnviar = new Button("Enviar");
p.add(bEnviar, BorderLayout.EAST);
return p;
}

public static void main(String[] args) {


chat c = new chat();
}
}

Comparación entre Swing y AWT


Considere una aplicación que muestra un objeto de tipo Button (paquete java.awt).
En una computadora que ejecuta el sistema operativo Microsoft Windows, el
objeto Button tendrá la misma apariencia que los botones en las demás
aplicaciones Windows. De manera similar, en una computadora que ejecuta el
sistema operativo Apple Mac OS X, el objeto Button tendrá la misma apariencia
visual que los botones en las demás aplicaciones Macintosh. Algunas veces, la
forma en la que un usuario puede interactuar con un componente específico del
AWT difiere entre una plataforma y otra

La API de AWT es muy limitada y no provee componentes fundamentales como


árboles, grillas y solapas (entre otras limitaciones). Generalmente, las interfaces
gráficas se desarrollan con Swing. Cabe aclarar que todas las clases de Swing
heredan de clases de AWT.

Para finalizar, debemos aclarar que todo el manejo de eventos y de layouts es


exactamente el mismo para Swing y para AWT.

1.2. EVENTOS

Cuando el usuario interactúa con la interfaz gráfica lo hace a través de sus


componentes. Cada acción que realiza (esto es: cada botón que presiona, cada
ítem que selecciona sobre una lista, cada carácter que escribe sobre un campo de
texto, etc.) genera un evento y nosotros, como programadores, lo podemos
“escuchar” para notificarnos y así poder hacer en ese momento lo que sea
necesario.

Es decir, los componentes generan eventos y nosotros podemos “escucharlos” (o


notificarnos) utilizando listeners (escuchadores). Un listener no es más que un
objeto cuya clase implementa una determinada interface, que está relacionado a
un componente para que este lo notifique ante la ocurrencia de un determinado
tipo de evento

Un evento es la notificación que hace un elemento gráfico cuando el usuario


interactúa con él. Por lo tanto, si se realiza alguna acción sobre algún elemento de
la interfaz, se dice que se ha generado un evento en dicho elemento.

Los eventos son las clases o interfaces que permiten crear objetos que capturen y
manejen los eventos. Un evento es una acción sobre algún componente, por
ejemplo, clic a un botón, pulsar la tecla de Enter en un botón, mover un elemento
con las teclas de navegación, eventos especiales como los programados por
tiempo, etc. Sin los eventos las GUI serían interfaces gráficas sin vida, y por lo
tanto no serían muy útiles que digamos.

Clases de eventos principales en java.awt.event

Clase de evento Descripción


ActionEvent Se genera cuando se presiona un botón, se hace doble
clic en un elemento de una lista, o se selecciona un
elemento de tipo menú.
AdjustmentEvent Se genera cuando se manipula un scrollbar.
ComponentEvent Se genera cuando un componente se oculta, se mueve,
se cambia de tamaño o se hace visible.
ContainerEvent Se genera cuando se añade o se elimina un
componente de un contenedor.
FocusEvent Se genera cuando un componente gana o pierde el
foco.
InputEvent Superclase abstracta de cualquier clase de evento de
entrada de componente.
ItemEvent Se genera cuando se hace click en un checkbox o en
un elemento de una lista; también ocurre cuando se
hace una selección en una opción choice o cuando se
selecciona o deselecciona un elemento de un menú de
opciones.
KeyEvent Se genera cuando se recibe una entrada desde el
teclado.
MouseEvent Se genera cuando el ratón se arrastra, se mueve, se
hace clic, se presiona, o se libera; también se genera
cuando el ratón entra o sale de un componente.
TextEvent Se genera cuando se cambia el valor de un área de
texto o un campo de texto
WindowEvent Se genera cuando una ventana se activa, se cierra, se
desactiva, se minimiza, se maximiza, se abre, o se sale
de ella.

Tipos de eventos

Eventos de bajo nivel.


Son las acciones elementales que hacen posible los eventos de alto nivel y que se
producen con las operaciones elementales de los componentes
(ComponentEvent), con los containers (ContainerEvent), con pulsar teclas
(KeyEvent), con todo lo que tenga que ver con el uso del ratón (MouseEvent), con
obtener o perder el focus (FocusEvent) y con las operaciones con ventanas
(WindowEvent)

Representan entradas o interacciones de bajo nivel con elementos del interfaz


gráfico (Cambio de tamaño, cambio del foco, operación con el ratón o con el
teclado).

 ComponentEvent: Se producirá este tipo de evento cuando el usuario


mueva o redimensione un componente.
 FocusEvent: Se producirá este tipo de evento cuando se cambie el foco de
un componente. El foco hace referencia al componente en el que estamos
trabajando.
 MouseEvent: Se producirá cuando el usuario efectúe un movimiento con el
ratón o haga un click.
 WindowEvent: se producirá cuando se realice algún tipo de operación con
la ventana como abrirla y cerrarla.
 ActionEvent: Se producirá cuando se efectúe alguna acción sobre un
componente, como por ejemplo: al presionar un botón.

Eventos semánticos o de alto nivel.


Son los que tienen que ver con clicar botones o elegir comandos (ActionEvent),
cambiar valores en barras de desplazamiento (AdjustmentEvent), elegir valores
(ItemEvents) o cambiar el texto (TextEvent).

Eventos de alto nivel que encapsulan la semántica del modelo de componentes


del interfaz de usuario (Hacer una acción, un cambio de estado en un
elemento, etc.).
No están relacionados con una clase específica de componente sino que pueden
aplicarse a todos los componentes que implementen un modelo semántico similar.
1.3. Manejo de eventos.

Pasos para el manejo de eventos


 Crear los componentes.
 Crear los oyentes (Listener) de los componentes, según los tipos de
eventos que se quiere capturar.
 Asociar los oyentes a los componentes.
 Gestionar los eventos con los métodos relacionado con los oyentes
definidos.

Jerarquía de eventos en JAVA

Para cada categoría de eventos, hay una interface que tiene que ser
implementada por la clase de objetos que quieren recibir los eventos. Esta
interface demanda que uno o más métodos sean definidos. Aquellos métodos son
llamados cuando un suceso o evento en particular surge. La siguiente tabla lista
estas interfaces por categorías.
Generación y propagación de eventos.
La clase padre de los eventos es: java.awt.Event

El paquete java.awt.event es el que contiene la mayor parte de las clases e


interfaces de eventos. El modelo de delegación de eventos es un concepto que
trabaja de la siguiente manera:

Una fuente de un evento es el generador de un evento, así por ejemplo, el clic del
ratón sobre un componente botón genera un ActionEvent con el botón como
origen o fuente del evento, ver figura siguiente. La instancia de un ActionEvent es
un objeto que contiene información acerca de los eventos que acaban de darse.
Este contiene:

El usuario da clic en el botón

Action Event
public void actionPerformed(ActionEvent e) {
System.out.println("Se presiono el boton 1...");
}

Capturar eventos
Cuando el usuario interactúa con la interfaz gráfica lo hace a través de sus
componentes. Cada acción que realiza (esto es: cada botón que presiona, cada
ítem que selecciona sobre una lista, cada carácter que escribe sobre un campo de
texto, etc.) genera un evento y nosotros, como programadores, lo podemos
“escuchar” para notificarnos y así poder hacer en ese momento lo que sea
necesario.
Es decir, los componentes generan eventos y nosotros podemos “escucharlos” (o
notificarnos) utilizando listeners (escuchadores). Un listener no es más que un
objeto cuya clase implementa una determinada interface, que está relacionado a
un componente para que este lo notifique ante la ocurrencia de un determinado
tipo de evento.
Para ejemplificar el uso de eventos usaremos la primer interfaz que se generó,
Ventana

public class Ventana extends Frame{

//definir los objetos


private Button b1,b2,b3;

public Ventana(){
//el consturctor padre recibe el titulo de la ventana
super("Mi primer ventana");

//definimos la distribucion de componentes


setLayout(new FlowLayout(FlowLayout.LEFT));

//instanciar los objetos y agregalos al contenedor (container)


b1=new Button("Boton 1");
add(b1);

// agrego un listener al boton


b1.addActionListener(new EscuchaBoton());
b2 = new Button("Boton 2");
add(b2);
b2.addActionListener(new EscuchaBoton2());

b3 = new Button("Boton 3");


add(b3);

//definir tamaño a la ventana y hacerla visible


setSize(300,300);
setVisible(true);
}

public static void main(String[] args) {


Ventana v=new Ventana();
}

class EscuchaBoton implements ActionListener {

public void actionPerformed(ActionEvent e) {


System.out.println("Se presiono el boton 1...");
}
}

En el constructor vemos que luego de instanciar el botón lo relacionamos con una


instancia de la inner class EscuchaBoton. Esta clase implementa la interface
ActionListener de donde hereda un único método: actionPerformed. Cuando el
botón detecte que lo están presionando notificará a la instancia de EscuchaBoton
invocándole el método actionPerformed.

Dicho de otro modo, cuando se presione el botón se invocará “automáticamente”


el método actionPerformed de la clase EscuchaBoton, por lo tanto, todo lo que
programemos dentro de este método se ejecutará exactamente en el momento en
que el usuario apriete el botón.

Es común implementar los listeners como inner classes de la GUI ya que, por lo
general, las acciones que se programan dentro de estos son propias y exclusivas
para los componentes de la interfaz gráfca, por lo que muy difícilmente puedan ser
reutilizados.

A continuación, veremos un ejemplo más simpático en el que cambiamos


aleatoriamente la ubicación de la ventana cada vez que se presiona el botón. Solo
veremos el código del listener ya que en la ventana principal no cambia nada.

class EscuchaBoton2 implements ActionListener {

public void actionPerformed(ActionEvent e) {


// dimension de la ventana
Dimension dimVentana = getSize();
// dimension de la pantalla
Dimension dimScreen = getToolkit().getScreenSize();
// nuevas coordenadas (aleatorias) para reubicar la ventana
int x = (int) (Math.random()* (dimScreen.width - dimVentana.width));
int y = (int) (Math.random() * (dimScreen.height - dimVentana.height));
// cambio la ubicacion de la ventana
setLocation(x, y);
}
}

Pensemos en un programa más divertido. ¿Cómo podríamos lograr que la ventana


cambie de posición cuando el mouse está llegando al botón para presionarlo? Es
decir, que el usuario nunca pueda apretar el botón porque ni bien aproxime el
mouse la ventana se moverá a otra posición.

Para programar esto, tenemos que escuchar el evento de movimiento del mouse.
Por cada movimiento del mouse, preguntamos sus coordenadas y las
comparamos con las coordenadas del botón. Si la distancia es razonablemente
corta, entonces movemos la ventana como lo hicimos en el ejemplo anterior.
public class Ventana extends Frame {

//definimos tres objetos Button


private Button b1, b2, b3;

public Ventana() {
//el constructor padre recibe el titulo de la ventana
super("Mi primer ventana");
// relaciono un WindowListener con el Frame
addWindowListener(new EscuchaVentana());

// quien genera el evento es el Frame


//addMouseMotionListener(new EscuchaMouse());

//definimos el layout que tendra la ventana: FlowLayout


setLayout(new FlowLayout(FlowLayout.LEFT));

//Instaciamos los objetos y los agregamos al contenedor (container)


b1 = new Button("Boton 1");
add(b1);

// agrego un listener al boton


b1.addActionListener(new EscuchaBoton());

b2 = new Button("Boton 2");


add(b2);
b2.addActionListener(new EscuchaBoton2());

b3 = new Button("Boton 3");


add(b3);

//definir el tamaño de la ventana y hacerla visible


setSize(300, 300);
setVisible(true);
}
public static void main(String[] args) {
Ventana v1 = new Ventana();
}

class EscuchaMouse implements MouseMotionListener {

public void mouseMoved(MouseEvent e) {


int distancia = 10;
Point pMouse = e.getPoint();
Dimension dimBoton = b3.getSize();
Point pBoton = b3.getLocation();
int difX1 = Math.abs(pBoton.x - pMouse.x);
int difX2 = Math.abs((pBoton.x + dimBoton.width) - pMouse.x);
int difY1 = Math.abs(pBoton.y - pMouse.y);
int difY2 = Math.abs((pBoton.y + dimBoton.height) - pMouse.y);
if (difX1 < distancia || difX2 < distancia || difY1 < distancia || difY2 < distancia) {
// dimension de la ventana
Dimension dimVentana = getSize();
// dimension de la pantalla
Dimension dimScreen = getToolkit().getScreenSize();
// nuevas coordenadas para la ventana
int y = (int) (Math.random()* (dimScreen.height - dimVentana.height));
int x = (int) (Math.random() * (dimScreen.width - dimVentana.width));
// cambio la ubicacion de la ventana
setLocation(x, y);
}
}

public void mouseDragged(MouseEvent e) {


}
}

En este ejemplo escuchamos el evento que la ventana (el Frame) genera cada vez
que el mouse se mueve dentro de su área. Por esto, le agregamos a la ventana
una instancia válida de MouseMotionListener (o sea, una instancia de
EscuchaMouse).

EscuchaMouse es una inner class que implementa MouseMotionListener y


sobrescribe los dos métodos defnidos en esta interface. El método mouseDragged
lo dejamos vacío porque no nos interesa ser notifcados cuando el usuario arrastra
el mouse (drag). Simplemente, queremos saber cuándo lo mueve. Dentro del
método mouseMoved, tomamos la posición del mouse, la posición del botón y su
dimensión para poder calcular la distancia entre el mouse y los cuatro lados del
botón. Si la distancia es menor que distancia, entonces movemos la ventana.

MANEJO DE CONTROL DE EVENTOS.

Creando múltiples interfaces


El mecanismo oyente permite agregar llamadas a un método addXxxListener()
tantas veces como sea necesario, y usted puede especificar muchos diferentes
oyentes como su diseño lo requiera. Todos estos oyentes registrados tienen sus
métodos manejadores que los invocan cuando un evento suceda.

Adaptadoras de eventos
Es mucho trabajo implementar todos los métodos en cada una de las interfaces
oyentes, particularmente para el caso de la interface MouseListener y
WindowListener.

Por ejemplo, la interface MouseListener declara los métodos siguientes:


public void mouseClicked( MouseEvent evento )
public void mouseEntered( MouseEvent evento )
public void mouseExited( MouseEvent evento )
public void mousePressed( MouseEvent evento )
public void mouseReleased( MouseEvent evento )

Como una conveniencia, el lenguaje de programación Java provee de clases


adaptadoras que implementan cada interface conteniendo más de un método. Los
métodos en estas clases adaptadoras están vacíos. Así, las clases oyentes que
usted define pueden extenderse en clases adaptadoras y sobrescribir solo los
métodos que usted necesite. Por ejemplo:

Manejo de eventos usando clases internas


Es posible implementar manejadores de eventos como clases internas ( como se
ve en la línea 23,46-54) . Esto permite el acceso a los datos privados de las clases
externas. Por ejemplo:

1 package unidad_1;
2
3 import java.awt.*;
4 import java.awt.event.MouseAdapter;
5 import java.awt.event.MouseEvent;
6 import java.awt.event.MouseMotionAdapter;
7
8 public class PruebaInterna {
9
10 private Frame f;
11 private TextField tf;
12
13 public PruebaInterna() {
14 f = new Frame("Ejemplo de Manejo de eventos con clases internas");
15 tf = new TextField(30);
16 } // fin del constructor
17
18 public void lanzaFrame() {
19 Label etiqueta = new Label(" Da clic o arrastra el ratón ");
20 // agrega componentes al Frame
21 f.add(etiqueta, BorderLayout.NORTH);
22 f.add(tf, BorderLayout.SOUTH);
23 // agrega un oyente que use una clase interna
24 f.addMouseMotionListener(new MiRatonseMueveOyente());
25 f.addMouseListener(new ManejadorClicRaton());
26
27 // Tamaño del frame y hacerlo visible
28 f.setSize(300, 200);
29 f.setVisible(true);
30 } // fin del método lanzaFrame()
31
32 class MiRatonseMueveOyente extends MouseMotionAdapter {
33
34 public void mouseDragged(MouseEvent e) {
35 String s = "Ratón arrastrandose: X = " + e.getX()
36 + " Y = " + e.getY();
37 tf.setText(s);
38 } // fin del método mouseDragged()
39 } // fin de la clase interna adaptadora MiRatonseMueveOyente
40
41 public static void main(String[] argumentos) {
42 PruebaInterna obj = new PruebaInterna();
43 obj.lanzaFrame();
44 } // fin del main()
45
46 public class ManejadorClicRaton extends MouseAdapter {
47 // necesitamos el manejador mouseClick, asi que usamos
48 // entonces el adaptador para evitar tener que escribir todos los
49 // métodos manejadores de eventos
50
51 public void mouseClicked(MouseEvent e) {
52 // Aquí programamos el evento del clic del ratón
53 }
54 } // fin de la clase ManejadorClicRaton
55 } // fin de la clase PruebaInterna
56

Usando clases internas anónimas


Es posible incluir la definición completa de una clase en el ámbito de una
expresión. Esta situación define lo que es conocido como clases internas
anónimas y crea la instancia de una de ellas. Las clases anónimas internas son
generalmente utilizadas con el manejo de eventos en AWT ; por ejemplo ver líneas
de la 22-29:

1 package unidad_1;
2
3 import java.awt.*;
4 import java.awt.event.*;
5
6 public class PruebaAnonima {
7
8 private Frame f;
9 private TextField tf;
10
11 public PruebaAnonima() {
12 f = new Frame("Ejemplo de Manejo de eventos con clases internas anónimas ");
13 tf = new TextField(30);
14 } // fin del constructor
15
16 public void lanzaFrame() {
17 Label etiqueta = new Label(" Da clic o arrastra el ratón ");
18 // agrega componentes al Frame
19 f.add(etiqueta, BorderLayout.NORTH);
20 f.add(tf, BorderLayout.SOUTH);
21
22 // agrega un oyente que use una clase interna anónima
23 f.addMouseMotionListener(new MouseMotionAdapter() {
24 public void mouseDragged(MouseEvent e) {
25 String s = "Ratón arrastrandose: X = " + e.getX()
26 + " Y = " + e.getY();
27 tf.setText(s);
28 }
29 }); // <-- observe que hay que cerrar el paréntesis
30
31
32 //f.addMouseListener(new ManejadorClicRaton());
33 // Tamaño del frame y hacerlo visible
34 f.setSize(300, 200);
35 f.setVisible(true);
36 } // fin del método lanzaFrame()
37
38 public static void main(String[] argumentos) {
39 PruebaAnonima obj = new PruebaAnonima();
40 obj.lanzaFrame();
41 } // fin del main()
42 } // fin de la clase PruebaAnonima

Conclusión: pasos definir GUIs


1. Crear los componentes.
2. Definir propiedades de los componentes.
3. Crear los contenedores para almacenar los componen definidos.
4. Especificar el LayoutManager de cada contenedor.
5. Añadir los componentes en los contenedores.
6. Definir los eventos que se van a capturar.
7. Crear los oyentes (Listener) de los eventos.
8. Asociar los eventos al componente.
9. Gestionar el comportamiento cuando se presente el evento, a través del
método implementado en el oyente.
ACTIVIDAD DE LA UNIDAD 1. CUESTIONARIO

Nombre:____________________________________________________________________ Grupo: _________

Instrucciones: Lee el material anterior para contestar el siguiente cuestionario

1. ¿Qué significan las siglas GUI?

2. ¿Cuál es la función de un componente?

3. Describe ¿qué es contenedor?

4. ¿Cuáles son los tipos de contenedores más comunes?

5. ¿Qué realiza el evento MouseEvent?

6. ¿Cuáles son las dos formas de trabajar GUIs en java?

7. ¿Cuál es la función de la clase JDialog?

8. ¿Cuáles son los cuatro métodos que implementa la clase jDialog?

9. Define ¿Qué es un layout?

10. Describe los tres tipos de layouts

11. ¿Qué es un evento?


12. ¿Cuáles son los tipos de eventos? Explícalos.

13. Menciona las formas para el control de eventos

14. ¿Qué es una clase anónima?

15. ¿Cuándo se utiliza una adaptadora de eventos?

16. ¿Qué es un ActionEvent?

17. ¿Qué es un TextEvent?

18. ¿Qué es un listener?

19. Nombre de la clase padre de los eventos en java

20. ¿Cuáles son los pasos para el manejo de eventos?

21. ¿Qué evento es el que controla las acciones de las ventanas?

22. ¿Cuál es el evento que controla las acciones realizadas por el teclado?

También podría gustarte