Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Apuntes de la Unidad 1
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 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 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:
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.
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:
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:
La clase JDialog puede utilizar todos los métodos descritos para la clase
JFrame.
//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 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] );
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.
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.*;
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 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);
}
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);
}
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 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);
}
1.2. EVENTOS
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.
Tipos de eventos
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
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:
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 Ventana(){
//el consturctor padre recibe el titulo de la ventana
super("Mi primer ventana");
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.
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 {
public Ventana() {
//el constructor padre recibe el titulo de la ventana
super("Mi primer ventana");
// relaciono un WindowListener con el Frame
addWindowListener(new EscuchaVentana());
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).
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.
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
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
22. ¿Cuál es el evento que controla las acciones realizadas por el teclado?