Sunteți pe pagina 1din 90

Programación en 

GUIs

Tema 3: Programación en 
entornos gráficos de usuario
1.Introducción 12.Cuadros de diálogo
2.Evolución histórica 13.Teclas rápidas
3.Características de la  14.Los “looks” de Swing
programación  en GUIs
4.Gestión de eventos
5.Arquitectura de una aplicación 
con GUI
7.Programación de GUIs en Java
8.Componentes Swing
9.Primeros pasos en Swing
10.Gestores de de distribución
11.Diseñando nuestro JFrame
12.Captura de eventos
Programación en 
GUIs

Introducción 
Entendemos por Interfaz Gráfica de Usuario (GUI) al 
software que permite la interacción entre el usuario y 
los servicios que proporciona el sistema operativo, 
utilizando para ello una representación gráfica intuitiva 
de alto nivel
La informática moderna no puede entenderse sin el 
impacto que supuso la generalización de los entornos 
gráficos de usuario a partir de los 80
Hoy en día, la mayor parte de las aplicaciones 
destinadas a usuarios finales se realizan para este tipo 
de entornos
Introducción
Programación en 
GUIs

La mayoría de los GUIs de propósito general siguen 
la llamada metáfora de escritorio, y utilizan un sistema 
de ventanas. Para la interacción con el usuario 
disponen de un número más o menos grande de 
elementos o widgets: botones, editores, etc.
No vamos a estudiar aquí las características de las 
interfaces de usuario, su diseño o implementación 
(asignatura Interfaz Persona­Ordenador)
Nos centraremos en las características de la 
programación en este tipo de entornos y en una 
descripción general del cambio que supone respecto a 
la programación clásica y las nuevas posibilidades que 
aporta
Introducción
Programación en 
GUIs

Evolución histórica 
La aparición de los GUIs fue posible por la mejora de 
las prestaciones de los ordenadores. La escasa 
potencia de los ordenadores hasta principios de los 70 
hacía impensable desperdiciar CPU en la interfaz con 
el usuario
Hasta entonces el usuario disponía de una mínima 
interfaz en modo texto, básicamente una línea donde 
se tecleaban los comandos del S.O., en un nivel muy 
cercano a la máquina

Evolución histórica
Programación en 
GUIs

Los orígenes

Alto (1973). Desarrollado en el Xerox PARC, Alto fue 
el primer ordenador que incorporaba ratón y un 
sistema operativo con una interfaz gráfica de usuario. 
Sin embargo su precio era prohibitivo, lo que impidió 
su difusión fuera del ámbito de universidades y 
centros de investigación 

Star (1981). Xerox desarrolló Star con la 
intención de presentar un ordenador personal 
para el ámbito de la ofimática. Implementa por 
primera vez la metáfora de escritorio y generaliza 
el uso de iconos y ventanas solapadas. Su 
influencia en Apple y el resto de GUIs que 
siguieron fue enorme  

Evolución histórica
Programación en 
GUIs

Los entornos operativos de Apple y Next

System 1 (1984). Steve Jobs tomo las 
ideas desarrolladas en el Xerox PARC para 
diseñar el sistema operativo del nuevo 
ordenador que iba a lanzar al mercado su 
compañía Apple, el Macintosh. Este 
ordenador acercó la informática al usuario 
doméstico como nunca antes había ocurrido

GS/OS (1988). El System 1 
evolucionó rápidamente hasta el 
GS/OS, que incorporaba explotaba el 
soporte de color (200x320x16 colores) 
y sonido del Apple IIGS, así como su 
mayor potencia. Los ordenadores 
Apple se hicieron populares por lo 
sencillo e intuitivo que era su uso

Evolución histórica
Programación en 
GUIs

System 7 (1991). Representó un enorme 
salto frente a los sistemas anteriores, al 
incluir soporte de red de forma 
transparente, direccionamiento de memoria 
de 32 bits y memoria virtual, así como 
tecnologías como Drag­and­drop, Quicktime 
(multimedia) y Truetype (fuentes mejorados)

NextStep (1988). Steve Jobs fue 
despedido de Apple y fundó una nueva 
compañía: Next. Los ordenadores Next y su 
sistema operativo NextStep estaban llenos 
de innovaciones y buen diseño. Como 
curiosidad, el lenguaje de programación 
nativo de NextStep eral el Objetive­C, un 
lenguaje OOP

Evolución histórica
Programación en 
GUIs

X­Window
El sistema X­Window fue desarrollado en el MIT en 1984, apareciendo la 
primera versión comercial en 1986. X­Window no era un GUI en sí, sino 
simplemente un sistema de ventanas con capacidad de funcionar a través de 
la red. Para trabajar con X­Window era necesario un gestor de ventanas, que 
era el que proporcionaba el look­and­feel definitivo

TWM. Fue uno de los primeros 
gestores de ventanas para X. 
Realmente proporcionaba lo mínimo 
para trabajar con la máquina

Evolución histórica
Programación en 
GUIs

Motif. El primer gestor de ventanas 
para X­Window que proporcionaba una 
buena calidad de presentación. 
Durante años el toolkit de 
programación Motif ha sido el 
predilecto para los programadores en 
X­Window

OpenWindows. Ha sido el gestor de 
ventanas utilizado por SUN durante 
años. De características similares a 
Motif, con un look muy peculiar. Las 
primeras versiones de Linux también 
utilizaban este gestor de ventanas, 
antes de la aparición de Gnome y KDE

Evolución histórica
Programación en 
GUIs

KDE. Fue desarrollado para Linux, 
con la intención de competir con 
Windows en aspecto, facilidad de uso 
y cantidad de aplicaciones. El toolkit 
de programación es Qt de la compañía 
Trolltech para C++

Gnome. Es fruto de un proyecto que 
surgió con el objetivo de construir un 
gestor de ventanas igual o mejor que 
KDE pero utilizando un toolkit abierto 
desarrollado por la comunidad (GTK). 
Sin embargo el resultado no llega al 
nivel de KDE. Además GTK está 
basado en C, y no es ni de lejos tan 
fácil de usar y potente como Qt

Evolución histórica
Programación en 
GUIs

Windows y OS/2
Windows 1.0 (1985). Fue un intento 
de Microsoft para implantar la filosofía 
de los GUIs de Apple en la plataforma 
PC. El resultado era realmente 
bastante pobre. Su repercusión fue 
francamente escasa

Windows 3.1 (1992). El primer GUI de 
Microsoft con verdadero éxito, 
Responsable del gran salto del PC al 
“modo gráfico”. Era todavía inferior en 
prestaciones a los GUIs de Apple, 
aunque la distancia se acortaba.   

Evolución histórica
Programación en 
GUIs

OS/2 (1992). El entorno operativo de 
IBM, con la intención de competir con 
Windows en el mercado de los PCs. 
Era superior a Windows 3.1 y tuvo 
cierta popularidad. OS/2 no era un 
simple entorno gráfico de ventanas, sin 
un sistema operativo completo de 32 
bits, no basado en MS­DOS

Windows 95 (1995). Visual y 
funcionalmente representó un gran 
salto desde Windows 3.1 aunque 
internamente seguía siendo un 
sistema operativo de 16 bits

Evolución histórica
Programación en 
GUIs

Características de la programación en GUIs 
La programación en un GUI determinado requiere el 
uso de un toolkit (o SDK) para ese GUI, en el lenguaje 
de programación que queramos utilizar
Existe siempre un toolkit “oficial” que proporciona el fabricante del GUI, 
normalmente para C o C++. Por ejemplo MFC para programación en Windows
También existen toolkits alternativos desarrollados por terceros, ya sean 
comerciales o gratuitos. Por ejemplo, OWL (C++) de Borland para Windows
Finalmente también es posible el uso de un toolkit multiplataforma, como GTK+ 
(para C), Qt o Fltk (ambos para C++)
La estructura de un GUI es de forma natural orientada 
a objetos. El desarrollo con un toolkit orientado a 
objetos es mucho más sencillo y rápido

Características de la 
programación en GUIs
Programación en 
GUIs

La programación de aplicaciones para un GUI implica  
un cambio radical de filosofía y estructura en los 
programas
Un programa tradicional tiene una estructura “lineal”, 
con el código repartido en una serie de funciones u 
operaciones. Existe una función u operación principal 
donde comienza la ejecución y a partir de ahí se 
encadenan las llamadas de unas funciones a otras 
hasta que en un punto determinado acaba la ejecución

Inicio Tarea Programa


1 Tarea 2 ... Tarea n Fin

Características de la 
programación en GUIs
Programación en 
GUIs

En cambio la programación en GUIs es orientada a 
eventos. La mayoría de los eventos son sucesos 
asíncronos producidos por la interacción del usuario 
con la aplicación, y están ligados a algún elemento de 
la interfaz. Algunos ejemplos son:
Pulsar un botón
Cambiar el tamaño de una ventana
Mover una barra de desplazamiento
Pulsar una tecla 
Tocar alguno de los botones minimizar­maximizar­cerrar de la ventana
Hacer un click de ratón sobre un elemento determinado
Algunos eventos no relacionados directamente con el 
usuario son:
Aparición de una ventana
“Tick” de un reloj programado con antelación

Características de la 
programación en GUIs
Programación en 
GUIs

La mayor parte del código en un programa para un GUI 
está en los llamados manejadores de eventos. Cada 
manejador se encarga de realizar el conjunto de 
acciones asociadas a un evento determinado. Existe un 
gestor de eventos (que puede proporcionar el toolkit) 
que se encarga de recibir todos los eventos de la 
aplicación y llamar al manejador adecuado

Manejador 1

Manejador 2

Inicialización Gestor de
Inicio Fin
eventos
Manejador 3

Manejador 4

Características de la 
programación en GUIs
Programación en 
GUIs

La programación en GUIs suele ser un proceso iterativo 
 de tres pasos
El primero consiste en diseñar la interfaz de una parte 
de la aplicación, utilizando los widgets disponibles en el 
toolkit de desarrollo e incluye dos tareas:
Posicionar los widgets y establecer sus dimensiones
Modificar sus características visuales y funcionales (títulos, colores, 
comportamiento)
En el segundo se realiza la captura de los eventos de la 
interfaz que permitan implementar la funcionalidad 
requerida
En el tercer paso, se implementa cada uno de los 
manejadores correspondientes a los eventos capturados

Características de la 
programación en GUIs
Programación en 
GUIs

Los entornos modernos orientados a componentes 
como Delphi, C++ Builder, Visual Basic etc. permiten 
realizar las dos primeros pasos de manera “visual” en lo 
que se conoce como fase de diseño

Características de la 
programación en GUIs
Programación en 
GUIs

Una vez realizado el diseño, los entornos de desarrollo 
eligen una de las siguientes estrategias:
Salvar el diseño y las propiedades en ficheros ocultos especiales que son 
compilados junto al código (Delphi, C++ Builder, Visual Basic) 
Generar el código correspondiente de la interfaz que el desarrollador completa con 
su propio código (NetBeans) 

Características de la 
programación en GUIs
Programación en 
GUIs

Gestión de eventos
Como acabamos de ver, en un programa para un GUI 
la tarea fundamental a realizar es gestionar adecuada­
mente los eventos recibidos
La información asociada a un evento suele ser como 
mínimo un campo indicador del tipo de evento y el 
identificador del elemento que genera dicho evento 
(botón, ventana, etc.)
Un aspecto fundamental en el diseño de un toolkit es 
la forma en que se produce la conexión entre el gestor 
de eventos y los manejadores

Gestión de eventos
Programación en 
GUIs

En los toolkits más básicos y primitivos, que suelen 
ser para el lenguaje C, el programador realiza la 
implementación del gestor de eventos y la llamada 
directa a los distintos manejadores
Durante la inicialización de la aplicación debe pasarse 
al toolkit el nombre de nuestro gestor de eventos
int main() {
...
/* Indicar al toolkit la función para la gestión de eventos */
gestorEventosGUI(gestorEventos);
...
}

void gestorEventos(Evento e)
{
switch(e.tipo) {
case VENTANA_ABRIR: ventanaAbrir(e); break;
case VENTANA_CERRAR: ventanaCerrar(e); break;
case BOTON_PULSADO: botonPulsado(e); break;
...
}
}
Gestión de eventos
Programación en 
GUIs

En toolkits más sofisticados es posible indicar por 
cada evento que nos interese una función que hace 
las veces de manejador (CALLBACK). El gestor de 
eventos está integrado en el toolkit
El uso de CALLBACKs suele favorecer el uso de 
elementos no muy aconsejables: variables y objetos 
globales, punteros a void, etc.
int main() {
...
/* Indicar al toolkit los distintos manejadores */
manejadorEventoGUI(VENTANA_ABRIR, ventanaAbrir);
manejadorEventoGUI(VENTANA_CERRAR, ventanaCerrar);
manejadorEventoGUI(BOTON_PULSADO, botonPulsado);
...
}

Gestión de eventos
Programación en 
GUIs

Java utiliza un sistema basado en el patrón de diseño 


Observador
El elemento que genera un evento admite una lista de 
observadores del mismo
El elemento enviará una notificación a los observadores 
cada vez que se genere el evento
// Definición de una clase observador del procesamiento de pulsaciones de botón
class procesamientoBoton implements ActionListener {
void actionPerformed(ActionEvent e)
{
// Procesar evento de pulsación de botón
}
}

// Suscribir el observador procesamientoBoton al evento de pulsación de este botón


boton1.addActionListener(new procesamientoBoton());

Gestión de eventos
Programación en 
GUIs

Otros toolkits com Qt disponen de mecanismos 
específicos. Incorpora una extensión a C++ que permite 
enlazar un evento producido por un elemento con una 
operación de un objeto determinado (SIGNAL/SLOT)
MFC también hace uso extensivo de macros especiales 
para conectar los eventos con ciertas operaciones de la 
clase que realizan su procesamiento

Gestión de eventos
Programación en 
GUIs

Arquitectura de una aplicación con GUI
La arquitectura de una aplicación con GUI tiene una 
serie de niveles que engloban clases que realizan 
distintas tareas
Capa de presentación o interfaz
Capa de aplicación o del dominio del problema
Capa de persistencia

Capa de presentación

Capa de aplicación

Capa de persistencia

Arquitectura de una 
aplicación GUI 
Programación en 
GUIs

La capa de presentación o interfaz contiene los objetos 
que permiten mostrar la información al usuario y 
gestionar la interacción con el mismo. Atención: es 
dependiente del toolkit utilizado
La capa de aplicación o de dominio del problema 
contiene las objetos que modelan la solución del 
problema (objetos de negocio). Es la capa más 
importante y puede ser reutilizada total o parcialmente 
en múltiples aplicaciones similares
La capa de persistencia contiene el código necesario 
para almacenar los objetos de negocio en bases de 
datos o ficheros. Puede ser dependiente de la base de 
datos/formato de fichero utilizado
Arquitectura de una 
aplicación GUI 
Programación en 
GUIs

Es fundamental respetar siempre esta división de 
tareas entre las clases de una aplicación
Mezclar en una misma clase aspectos funcionalidades 
de estos tres niveles es un grave fallo de diseño con 
diversas consecuencias
Propensión a errores
Dificultad para entender su funcionamiento
Mantenimiento y localización de errores compleja
Imposibilidad de reutilización
Otra regla importante a seguir es procurar que las 
clases de cada nivel se comuniquen únicamente con las 
del nivel inmediatamente inferior
En la asignatura Interfaz Persona­Ordenador se 
estudiará con mayor detalle este tema
Arquitectura de una 
aplicación GUI 
Programación en 
GUIs

Programación de GUIs en Java
Puesto que Java pretende ser un lenguaje multipla­
taforma, el diseño del toolkit para programación de GUIs 
se hizo pensando en que las aplicaciones tuvieran un 
buen aspecto en cualquier plataforma pero indepen­
diente de cualquier GUI específico
Este toolkit se denominó AWT 1.0 (Abstract Window 
Toolkit) 

Programación 
de GUIs en Java
Programación en 
GUIs

Realmente las aplicaciones AWT 1.0 tenían un aspecto 
mediocre y un escaso número de elementos. Además su 
diseño interno era muy deficiente
La situación mejoró algo con AWT 1.1, pero no fue 
hasta Java 1.2 cuando apareció Swing, un toolkit 
completamente nuevo, con un diseño interno orientado a 
componentes y un look mucho más satisfactorio

Programación 
de GUIs en Java
Programación en 
GUIs

A pesar de que Swing tiene un estilo visual propio por 
defecto, puede también utilizar un aspecto “Motif”, 
“Windows” o “Apple”. Estos últimos sólo en las 
plataformas correspondientes. Además puede cambiar 
de aspecto en tiempo de ejecución

Aspecto Swing por defecto
Aspecto Windows

Aspecto Motif Programación 
de GUIs en Java
Programación en 
GUIs

Componentes de Swing
Componentes contenedores (sirven para contener y 
organizar otros compontes):

JFrame. Representa una ventana básica, capaz de 
contener otros componentes. Casi todas las 
aplicaciones construyen al menos un JFrame

JDialog, JOptionPane, etc. Los cuadros de diálogo 
son JFrame restringidos,  dependientes de un 
JFrame principal. Los JOptionPane son cuadros de 
diálogo sencillos predefinidos para pedir 
confirmación, realizar advertencias o notificar errores. 
Los JDialog son cuadros de diálogo generales, 
normalmente utilizados para peticiones de datos 

Componentes de 
Swing
Programación en 
GUIs

JInternalFrame. Consiste simplemente en una 
ventana hija, que no puede salir de los límites 
marcados por la ventana principal. Es muy común en 
aplicaciones que permiten tener varios documentos 
abiertos simultáneamente

JPanel. Un panel sirve para agrupar y organizar 
otros componentes. Puede estar decorado mediante 
un borde y una etiqueta

JScrollPane. Es un panel que permite visualizar un 
componente de un tamaño mayor que el disponible 
mediante el uso de barras de desplazamiento

Componentes de 
Swing
Programación en 
GUIs

JSplitPane. Permite visualizar dos componentes, 
uno a cada lado, con la posibilidad de modificar la 
cantidad de espacio otorgado a cada uno 

JTabbedPane. Permite definir varias hojas con 
pestañas, que pueden contener otros componentes. 
El usuario puede seleccionar la hoja que desea ver 
mediante las pestañas

JToolBar. Es un contenedor que permite agrupar 
otros componentes, normalmente botones con iconos 
en una fila o columna. Las barras de herramientas 
tienen la particularidad de que el usuario puede 
situarlas en distintas configuraciones sobre el frame 
principal  

Componentes de 
Swing
Programación en 
GUIs

Controles básicos:
JButton, JCheckBox, JRadioButton. Distintos tipos de 
botones. Un check box sirve para marcar una opción. Un 
radio button permite seleccionar una opción entre varias 
disponibles

JComboBox. Las combo boxes o listas desplegables que 
permiten seleccionar un opción entre varias posibles

JList. Listas que permiten seleccionar uno o más 
elementos
JTextField, JFormattedTextField, JPasswordField. 
Distintos tipos de editores. JFormattedTextField permite 
indicar el conjunto de caracteres legales que pueden 
introducirse. JPasswordField no muestra el contenido

JSlider. Un slider permiten introducir un valor 
numérico entre un máximo y un mínimo de manera 
rápida  Componentes de 
Swing
Programación en 
GUIs

JSpinner. Permiten seleccionar un valor entre un rango de 
opciones posibles, al igual que las listas desplegables, 
aunque no muestran tal lista. Los valores cambian al pulsar 
los botones de desplazamiento. También se puede introducir 
un valor directamente

Menús desplegables. Existen dos tipos de menús: 
JMenuBar, que consiste en una barra de menús 
desplegables en la parte superior de la aplicación, y 
JPopupMenu, un menú que se obtiene al pulsar con el botón 
derecho del ratón sobre una zona determinada. Los menús 
están compuestos por distintos items: JSeparator (una línea 
de separación entre opciones), JMenuItem (una opción 
ordinaria), JMenu (un submenu), JCheckboxMenuItem (un 
opción en forma de check box) o finalmente  
JRadioButtonMenuItem (una opción en forma de radio 
button

Componentes de 
Swing
Programación en 
GUIs

Controles especializados:

JColorChooser. Consiste en un selector de colores

JFileChooser. Permite abrir un cuadro de diálogo para pedir 
un nombre de fichero

JTable. Permite visualizar una tabla de información, con 
capacidad para permitir la edición por parte del usuario. La 
tabla puede incluir texto, imágenes y algunos controles 
básicos como check buttons y combo boxes

JTree. Su función es mostrar información de tipo jerárquico

Componentes de 
Swing
Programación en 
GUIs

Controles no interactivos (muestran algún tipo de 
información pero no interaccionan con el usuario):

JLabel. Permite situar un texto, un texto con una imagen o 
una imagen únicamente en la ventana. No son iteractivos y 
puede utilizarse código HTML para escribir texto en varias 
líneas y con varios atributos

JProgressBar. Permite mostrar que porcentaje del total de 
una tarea a realizar ha sido completado

JToolTip. Consiste en una etiqueta de ayuda que surge al 
cabo de uno segundos sobre la posición apuntada por el 
cursor. Normalmente no es necesario utilizar directamente la 
clase JToolTip, se puede establecer para cualquier 
componente de la ventana mediante: e.setToolTipText(“Ésta 
es la etiqueta”) 

Componentes de 
Swing
Programación en 
GUIs

Primeros pasos en Swing
Casi siempre, el primer paso a la hora de construir una 
aplicación es crear un JFrame inicial
Por defecto un JFrame se crea de forma invisible, así 
que que es necesario activar su visualización mediante 
la operación setVisible()
import javax.swing.JFrame;

public class AppHolaMundo {


public static void main(String[] args) {
JFrame f = new JFrame("Prueba");

f.setVisible(true);
}
}

Primeros pasos
en Swing
Programación en 
GUIs

Sin embargo, al cerrar este frame la aplicación no 
termina, se queda “colgada”. Esto ocurre porque es 
necesario asociar la acción de cerrar el JFrame con la 
finalización de la aplicación
Podemos realizar esta asociación mediante la 
operación setDefaultCloseOperation()  
import javax.swing.*;

public class AppHolaMundo {


public static void main(String[] args) {
JFrame f = new JFrame("Prueba");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

f.setVisible(true);
}
}

Primeros pasos
en Swing
Programación en 
GUIs

Los componentes se añaden al panel de contenidos del 
JFrame, accesible mediante getContentPane().add()
El JFrame dispone de una operación add() que ya hace 
esto directamente
Vamos a crear un JLabel con el texto “Hola mundo” y lo vamos a añadir al  
JFrame. Con esto ya tenemos un “Hola mundo” en Swing
import javax.swing.JFrame;

public class AppHolaMundo {


public static void main(String[] args) {
JFrame f = new Jframe("Prueba");
// Equivalente a f.getContentPane().add(new JLabel...)
f.add(new Jlabel (“Hola mundo”));
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

f.setVisible(true);
}
}

Primeros pasos
en Swing
Programación en 
GUIs

Gestores de distribución
Una de las tareas más tediosas a la hora de diseñar un 
frame con varios elementos en el interior es posicionar y 
establecer el tamaño de cada uno de estos elementos. 
Dos alternativas:
Posicionar cada uno los elementos indicando posiciones y tamaños. Es tedioso si 
no se realiza de forma interactiva. Además al cambiar el tamaño del frame los 
elementos pueden desajustarse
Utilizar un gestor de distribución que se encarga de distribuir los componentes de 
forma automática. Puede ser complicado obtener la distribución que realmente 
deseamos

Gestores de 
distribución
Programación en 
GUIs

En la programación con Swing se recomienda el uso de 
un gestor de distribución (LayoutManager) para la 
distribución de los componentes en frames y cuadros de 
diálogo
Podemos establecer el gestor de distribución para los 
elementos situados en un panel mediante 
panel.setLayout(<gestor de distribución>)
Podemos anular la distribución automática mediante 
panel.setLayout(null) e indicar coordenadas absolutas
Para establecer el tamaño del frame que contiene los 
componentes tenemos igualmente dos opciones:
Utilizar frame.pack() para que ajuste su tamaño al de los componentes de su 
interior. Esta es la opción más recomendable
Establecer su tamaño indicando ancho y alto mediante frame.setSize()
Gestores de 
distribución
Programación en 
GUIs

Vamos a diseñar una interfaz para el ejemplo de la cuentas bancarias del tema 2. 
Empezaremos añadiendo etiquetas (JLabel) y editores (JTextField) para poder 
visualizar la información de la cuenta
public class AppBanco {
public static void main(String[] args) {
JFrame f = new JFrame("Gestión de Cuentas");

f.add(new JLabel ("Código"));


f.add(new JTextField (8));
f.add(new JLabel ("Titular"));
f.add(new JTextField (30));
f.add(new JLabel ("Saldo"));
f.add(new JTextField (8));
f.add(new JLabel ("Interés"));
f.add(new JTextField (4));

f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

f.setVisible(true);
}
}

El resultado no es correcto por dos razones. En primer lugar Swing utiliza por 
defecto el gestor de distribución BorderLayout que no es válido para nuestro 
ejemplo. Además la ventana no tiene el tamaño adecuado para visualizar los 
componentes Gestores de 
distribución
Programación en 
GUIs

El gestor de distribución BorderLayout permite un 
componente pegado a uno de los bordes del panel o en 
el centro del mismo. Por defecto los componentes se 
situan junto al borde izquierdo 
public class AppBanco {
public static void main(String[] args) {
JFrame f = new JFrame("Gestión de Cuentas");

f.add(new JLabel("Este"), BorderLayout.WEST);


f.add(new JLabel("Centro"), BorderLayout.CENTER);
f.add(new JLabel("Oeste"), BorderLayout.EAST);
f.pack(); // Ajustar Frame a los contenidos

f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

f.setVisible(true);
}
}

Gestores de 
distribución
Programación en 
GUIs

El gestor de distribución BoxLayout organiza los 
componentes horizontal o verticalmente, ajustando los 
componentes al espacio disponible

public class AppBanco {


public static void main(String[] args) {
JFrame f = new JFrame("Gestión de Cuentas");

f.setLayout(
new BoxLayout(f.getContentPane(), BoxLayout.X_AXIS));
f.add(new JLabel("Código"));
f.add(new JTextField(8));
f.add(new JLabel("Titular"));
f.add(new JTextField(30));
f.add(new JLabel("Saldo"));
f.add(new JTextField(8));
f.add(new JLabel("Interés"));
f.add(new JTextField(4));
f.pack(); // Ajustar JFrame a los contenidos

f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

f.setVisible(true);
}
}
Gestores de 
distribución
Programación en 
GUIs

Utilizando el parámetro X_AXIS o Y_AXIS conseguimos 
una distribución horizontal o vértical

El gestor de distribución FlowLayout es similar al 
BoxLayout horizontal pero los componentes mantienen 
sus dimensiones

Gestores de 
distribución
Programación en 
GUIs

El gestor de distribución GridLayout organiza los 
componentes en una rejilla de celdas del mismo tamaño
public class AppBanco {
public static void main(String[] args) {
JFrame f = new JFrame("Gestión de Cuentas");

f.setLayout(new GridLayout(4,2));
f.add(new JLabel("Código"));
f.add(new JTextField(8));
f.add(new JLabel("Titular"));
f.add(new JTextField(30));
f.add(new JLabel("Saldo"));
f.add(new JTextField(8));
f.add(new JLabel("Interés"));
f.add(new JTextField(4));

f.pack(); // Ajustar Frame a los contenidos

f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

f.setVisible(true);
}
}

Gestores de 
distribución
Programación en 
GUIs

El gestor de distribución GridBagLayout es un 
organizador basado también en rejilla aunque más 
flexible, con capacidad para que los componentes 
ocupen varias celdas de distinto tamaño si es necesario
El gestor SpringLayout se basa en la especificación de 
distancias entre los bordes de los distintos 
componentes. Está pensado para el uso de un editor 
gráfico interactivo
También, aunque está desaconsejado, podemos anular 
el gestor de distribución y e indicar directamente 
posiciones y tamaños para los componentes

Gestores de 
distribución
Programación en 
GUIs

Ésta sería la forma de organizar la ventana principal de nuestro ejemplo de 
manera manual

public class AppBanco {


public static void main(String[] args) {
JFrame f = new JFrame("Gestión de Cuentas");
JLabel lc, lt;
JTextField tfc, tft;

f.setLayout(null);

f.add(lc = new JLabel("Código"));


f.add(tfc = new JTextField(8));
lc.setBounds(10, 10, 50, 20);
tfc.setBounds(70, 10, 50, 20);

f.add(lt = new JLabel("Titular"));


f.add(tft = new JTextField(30));
lt.setLocation(10, 40); lt.setSize(50, 20);
tft.setLocation(70, 40); tft.setSize(120, 20);

f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

f.setSize(320, 200);
f.setVisible(true);
}
}

Gestores de 
distribución
Programación en 
GUIs

La organización manual o mediante un gestor de 
distribución complejo únicamente resulta práctica 
mediante un editor gráfico

Gestores de 
distribución
Programación en 
GUIs

A efectos prácticos se usan la mayoría de las veces 
FlowLayout y BoxLayout, utilizando paneles internos 
para agrupar ciertos componentes
Vamos a utilizar tres JPanel para agrupar los componentes en tres grupos 
organizados mediante FlowLayout. A su vez estos tres paneles van a ser 
controlados por un BoxLayout

(BoxLayout Y_AXIS)
JPanel pc (FlowLayout)
Código

JPanel pt (FlowLayout)
Titular

JPanel psi (FlowLayout)
Saldo Interés

Gestores de 
distribución
Programación en 
public class AppBanco { GUIs
public static void main(String[] args) {
JFrame f = new JFrame("Gestión de Cuentas");

JPanel pc = new JPanel();


pc.setLayout(new FlowLayout(FlowLayout.LEFT));
pc.add(new JLabel("Código"));
pc.add(new JTextField(8));

JPanel pt = new JPanel();


pt.setLayout(new FlowLayout(FlowLayout.LEFT));
pt.add(new JLabel("Titular"));
pt.add(new JTextField(30));

JPanel psi = new JPanel();


psi.setLayout (new FlowLayout(FlowLayout.LEFT));
psi.add (new JLabel("Saldo"));
psi.add (new JTextField(8));
psi.add (new JLabel("Interés"));
psi.add (new JTextField(4));

f.setLayout (
new BoxLayout(f, BoxLayout.Y_AXIS));
f.add(pc);
f.add(pt);
f.add(psi);
f.pack(); // Ajustar Frame a los contenidos

f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

f.setVisible(true);
}
} Gestores de 
distribución
Programación en 
GUIs

Diseñando nuestro JFrame
Cuando un JFrame tiene cierta complejidad, lo más 
correcto y elegante es extender esta clase añadiendo 
todas las características que necesitemos
El constructor puede utilizarse para la creación de 
componentes, gestores de distribución,etc.
Los componentes pueden conectarse a referencias que 
sean atributos para tener acceso a ellos en múltiples 
operaciones de la clase
El enfoque utilizado hasta ahora en nuestra aplicación es válido únicamente para 
aplicaciones muy simples. Vamos a definir una nueva clase FAppCuenta a partir 
de JFrame
public class AppBanco {
public static void main(String[] args) {
FAppBanco f = new FAppBanco();
}
} Diseñando nuestro 
JFrame
import java.awt.*; Programación en 
import javax.swing.*; GUIs

public class FAppBanco extends JFrame {


JTextField tfc, tft, tfs, tfi;

public FAppBanco() {
super("Gestión de Cuentas Bancarias");

JPanel pc = new JPanel();


pc.setLayout(new FlowLayout(FlowLayout.LEFT));
pc.add(new JLabel("Código"));
pc.add(tfc = new JTextField(8));

JPanel pt = new JPanel();


pt.setLayout(new FlowLayout(FlowLayout.LEFT));
pt.add(new JLabel("Titular"));
pt.add(tft = new JTextField(30));

JPanel psi = new JPanel();


psi.setLayout (new FlowLayout(FlowLayout.LEFT));
psi.add(new JLabel("Saldo"));
psi.add(tfs = new JTextField (8));
tfs.setEditable(false); // Establecermos a sólo lectura el saldo

psi.add(new JLabel("Interés"));
psi.add(tfi = new JTextField(4));

setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));


add(pc);
add(pt);
add(psi);
pack();

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
}
Diseñando nuestro 
JFrame
Programación en 
GUIs

Usaremos este esquema con las clases JFrame, 
JInternalFrame o JDialog, cuando contengan un número 
relevante de componentes con una gestión más o 
menos compleja, incluyendo captura y procesamiento de 
eventos
En estos casos la nueva clase definida, además de ser 
en sí un componente de nuestra interfaz, tiene una 
segunda función muy importante de coordinación, 
gestión y procesamiento de la información que llega a 
través de sus componentes hijos
El enfoque utilizado hasta ahora en nuestra aplicación es válido únicamente para 
aplicaciones muy simples. Vamos a definir una nueva clase FAppCuenta a partir 
de JFrame

Diseñando nuestro 
JFrame
Programación en 
GUIs

Siguiendo con nuestro ejemplo, vamos a añadir una tabla para guardar los 
movimientos realizados en la cuenta
Lo primero que hay que hacer es crear una clase especial que va a suministrar la 
información a la tabla. Para ello podemos implementar la interfaz TableModel o 
extender la clase AbstractTableModel, que tiene ya implementaciones por defecto 
muchas de sus operaciones
Implementaremos esta clase como interior de FAppBanco

class InfoMovimientos extends AbstractTableModel {


private final String[] nombreCols = { "Fecha", "Tipo", "Importe", "Saldo" };

// Devolver el título de la columna indicada


public String getColumnName(int column) {
return nombreCols[column];
}
// Devolver el número de columnas de la tabla
public int getColumnCount() {
return 4;
}
// Devolver número de filas de la tabla
public int getRowCount() {
return 0; // De momento, ninguna
}
// Devolver valor en la posición (rowIndex, columnIndex) de la tabla
public Object getValueAt(int rowIndex, int columnIndex) {
return ""; // De momento, nada
}
}

Diseñando nuestro 
JFrame
Programación en 
GUIs

Normalmente la tabla debe ser insertada en un JScrollPane, ya que en caso 
contrario, al añadir muchas filas iría alargando la ventana paulatinamente hasta 
salir incluso de la pantalla
También vamos a añadir en la parte inferior cuatro botones para crear una 
cuenta, buscar una cuenta ya existente, realizar una operación y salir de la 
aplicación
class FAppBanco extends JFrame {
JTextField tfc, tft, tfs, tfi;
JButton bc, bb, bo, bs; // Nuevos atributos
InfoMovimientos im;
JTable tm;
// Resto de la clase a partir de aquí...

// Estamos en el constructor de FAppBanco...


JPanel pm = new JPanel(); // Crear panel de la tabla
pm.setLayout(new BorderLayout());

JLabel lm = new JLabel("Movimientos");


lm.setHorizontalAlignment(JLabel.CENTER);
pm.add(lm, BorderLayout.NORTH);

// Crear la tabla pasando un objeto de la clase InfoMovimientos


tm = new JTable(im = new InfoMovimientos());
JScrollPane sp = new JScrollPane(tm);
sp.setPreferredSize(400, 100);
pm.add(sp, BorderLayout.CENTER);
Diseñando nuestro 
JFrame
Programación en 
GUIs

// Crear panel de botones


JPanel pb = new JPanel(new FlowLayout(FlowLayout.CENTER));
pb.add(bc = new JButton("Crear"));
pb.add(bb = new JButton("Buscar"));
pb.add(bo = new JButton(“Operar”));
bo.setEnabled(false); // En principio el botón de operar está deshabilitado
pb.add(bc = new JButton(“Salir”));

setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));


add(pc);
add(pt);
add(psi);
add(pm); // Añadir el panel de la tabla
add(pb); // Añadir el panel de los botones
pack();

setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
setVisible (true);
} // Final del constructor de FAppBanco

Diseñando nuestro 
JFrame
Programación en 
GUIs

Captura de eventos
Como vimos al principio del tema, para la captura de 
eventos Swing usa un esquema a similar a los callbacks 
pero utilizando clases en lugar de funciones
Cada clase de captura de eventos (denominados event 
listeners) debe implementar una interfaz concreta en 
función del tipo de eventos que desea capturar
Una vez implementado el listener, bastará con indicar 
éste al componente del cual deseamos capturar los 
eventos

Captura de eventos
Programación en 
GUIs

Existen ciertos event listeners que son comunes a 
todos los componentes:
FocusListener: captura eventos relacionados con la recepción o pérdida del foco
KeyListener: captura pulsaciones de teclado sobre el componente activo
MouseListener: captura la entrada o salida del cursor sobre un componente, así 
como pulsaciones de los botones 
MouseMotionListener: captura movimientos del ratón sobre el componente
Otros son específicos de algunos componentes:
ActionListener: captura cierto tipo de acción realizada sobre ciertos componente. 
Por ejemplo, pulsar un botón, seleccionar un elemento en una lista desplegable o 
una opción en un menú
ChangeListener: registra los cambios sobre ciertos componente. Por ejemplo un 
cambio en el dato de un spinner, o un nuevo valor seleccionado en un slider
ItemListener: recoge el cambio de estado en un componente tipo on/off: check 
boxes, radio buttons y listas desplegables
ListSelectionListener: es un listener específico para detectar las selecciones 
múltiples realizadas en listas y tablas
WindowListener: permite recoger los eventos relacionados con las ventanas (cerrar, 
minimizar, maximizar, iconizar, etc.) en los frames, frames internos y cuadros de 
diálogo Captura de eventos
Programación en 
GUIs

Si la interfaz captura un único tipo de evento, como 
ActionListener, normalmente tendrá una única operación 
a implementar
void actionPerformed (ActionEvent e)
En cambio los listeners más complejos como 
FocusListener requieren la implementación de varias 
operaciones, cada una para un tipo de evento concreto
void focusGained (FocusEvent e)
void focusLost (FocusEvent e)
Cuidado: un listener puede tener un significado distinto 
dependiendo del componente (e.j. ActionListener)
Información detallada de cada listener: apartado 
“Listeners supported by Swing Components” del Tutorial 
Java de Sun
Captura de eventos
Programación en 
GUIs

Para las interfaces con más de una operación Swing 
proporciona por comodidad una clase adaptadora que 
implementa la interfaz mediante operaciones vacías
Cuando sólo necesitamos implementar una operación 
de la interfaz, extender la clase adaptadora es más 
cómodo
La clase adaptadora correspondiente se obtiene 
sustituyendo “Listener” por “Adapter”
Ejemplo: WindowListener  ­> WindowAdapter

Captura de eventos
Programación en 
GUIs

Hay dos formas básicas de implementar un listener:
Hacer que el JFrame que genera o contiene el componente generador del evento 
sea un listener, haciendo que implemente la interfaz correspondiente (lo más simple 
y eficiente)
Implementar una pequeña clase interior que haga de listener (lo más flexible)
Una vez implementado el listener, indicaremos al 
componente que lo utilice para notificar sus eventos 
mediante componente.add????Listener(objetoListener) 
donde ???? será el identificador del tipo de listener
Vamos a capturar el evento de pulsación del botón “Crear” y a realizar su 
implementación. En primer lugar declararemos la implementación de 
ActionListener por parte de la clase FAppBanco. También incluiremos un atributo 
para la cuenta actual
import java.awt.event.*; // Incluir las clases de eventos

class FAppBanco extends JFrame implements ActionListener {


Cuenta c;

// Continua la implementación de la clase FAppBanco...


Captura de eventos
Programación en 
GUIs

A continuación, implementaremos la única operación de esta interfaz y algunas 
operaciones auxiliares

public void actionPerformed(ActionEvent e) {


long codigo = comprobarCodigo();
if (codigo == -1) return;

float interes = comprobarInteres();


if (interes == -1) return;

salvarCuentaActual(); // Si existe una cuenta en memoria, salvarla

if (existeCuenta(codigo)) {
System.out.println(“La cuenta ya existe !”);
return;
}

c = new Cuenta(codigo, tft.getText(), interes); // Crear cuenta


tfs.setText("0.0"); // Por defecto el saldo a 0 inicialmente
bo.setEnabled(true); // Activar botón de operaciones
}

Captura de eventos
Programación en 
private long comprobarCodigo() { GUIs
long codigo;

try {
codigo = Long.parseLong(tfc.getText ());
if (codigo < 0)
throw new NumberFormatException();
}
catch(NumberFormatException nfe) {
System.out.println("Error en código de cuenta");
return -1;
}
return codigo;
}

private float comprobarInteres() {


float interes;
try {
interes = Float.parseFloat(tfi.getText ());
if (interes < 0 || interes > 100)
throw new NumberFormatException();
}
catch(NumberFormatException nfe) {
System.out.println("Error en el formato del interés");
return -1;
}
return interes;
}

public void salvarCuentaActual() {


if (c == null) return;

try {
c.salvar();
}
catch (IOException e) {
System.out.println("Error al salvar cuenta");
}
} Captura de eventos
Programación en 
GUIs

Finalmente indicaremos al botón “Crear” que envie los eventos al listener
// Estamos en el constructor de FAppBanco...

JPanel pb = new JPanel (new FlowLayout (FlowLayout.CENTER));


pb.add (bc = new JButton ("Crear"));
bc.addActionListener (this);
pb.add (bb = new JButton ("Buscar"));
pb.add (bo = new JButton ("Operación"));
bo.setEnabled (false);
pb.add (bs = new JButton ("Salir"));

// Continua el constructor...

La implementación mediante una clase interior sería la siguiente:


class FAppBanco extends JFrame {
Cuenta c;

JTextField tfc, tft, tfs, tfi;


JButton bc, bb, bo, bs; // Nuevos atributos
InfoMovimientos im;
JTable tm;

public class BotonCrearActionListener implements ActionListener {


public void actionPerformed (ActionEvent e) {
crearCuenta ();
}
}

// Continua la clase FAppBanco a partir de aquí...


Captura de eventos
Programación en 
GUIs

La operación crearCuenta () de FAppBanco incluiría el código de la creación de 
la cuenta (el mismo que la antigua función actionPerformed() de FAppBanco)
Finalmente conectaríamos el botón con el listener, creando un objeto de la clase 
BotonCrearActionListener
// Estamos en el constructor de FAppBanco...

JPanel pb = new JPanel (new FlowLayout (FlowLayout.CENTER));


pb.add (bc = new JButton ("Crear"));
bc.addActionListener (new BotonCrearActionListener ());
pb.add (bb = new JButton ("Buscar"));
pb.add (bo = new JButton ("Operación"));
bo.setEnabled (false);
pb.add (bs = new JButton ("Salir"));

// Continua el contructor...

No obstante, en nuestro ejemplo continuaremos siguiendo el primer método

Captura de eventos
Programación en 
GUIs

Un componente puede ser conectado a varios listeners 
del mismo o distintos eventos. De la misma forma, un 
listener puede ser conectado a varios componentes al 
mismo tiempo
En estos casos para determinar dentro del listener cuál 
es el componente que ha enviado el evento podemos 
utilizar la operación getSource() del evento recibido
Esta situación es muy frecuente cuando la clase 
principal hace de listener de los subcomponentes
Vamos a incluir en la operacion actionPerformed() de FAppBanco el código de
procesamiento de los botones “Crear”, “Buscar” y “Salir”

Captura de eventos
Programación en 
public void actionPerformed (ActionEvent e) {
GUIs
if (e.getSource () == bc) { // Botón “Crear”
long codigo = comprobarCodigo ();
if (codigo == -1) return;

float interes = comprobarInteres ();


if (interes == -1) return;

salvarCuentaActual ();

if (existeCuenta (codigo)) {
System.out.println ("Ya existe una cuenta con ese código");
return;
}

c = new Cuenta (codigo, tft.getText (), interes);


tfs.setText ("0.0");
bo.setEnabled (true);
}

if (e.getSource () == bb) { // Botón “Buscar”


long codigo = comprobarCodigo ();
if (codigo == -1) return;

try {
c = new Cuenta (codigo); // Cargar la cuenta

// Establecer los valores de la cuenta en los editores


tfc.setText (new Long (codigo).toString ());
tft.setText (c.leerTitular ());
tfs.setText (new Float (c.leerSaldo ()).toString ());
tfi.setText (new Float (c.leerInteres ()).toString ());
im.fireTableDataChanged (); // Actualizar tabla
bo.setEnabled (true);
}
catch (IOException ioe) {
System.out.println ("La cuenta no existe");
}
catch (ClassNotFoundException cnfe){} Captura de eventos
}
Programación en 
GUIs

if (e.getSource () == bs)
terminarAplicacion ();
}

private void terminarAplicacion () {


salvarCuentaActual (); // Salvar cuenta actual antes de salir
System.exit (0);
}

Vamos a incluir en la operacion actionPerformed() de FAppBanco el código de 
procesamiento de los botones “Crear”, “Buscar” y “Salir”

class InfoMovimientos extends AbstractTableModel {


private final String[] nombreCols = { "Fecha", "Tipo", "Importe", "Saldo" };
SimpleDateFormat sdf;

public InfoMovimientos () {
super ();

// Crear un formateador de fechas


sdf = new SimpleDateFormat ("dd.MM.yyyy HH:mm");
}

public String getColumnName (int column) {


return nombreCols[column];
}

public int getColumnCount() {


return 4;
}

Captura de eventos
Programación en 
GUIs

// Devolver número de elementos


public int getRowCount() {
if (c != null)
return c.numMovimientosHistorico ();
else
return 0;
}

// Devolver el campo número columnIndex del elemento número rowIndex


public Object getValueAt(int rowIndex, int columnIndex) {
Movimiento m = c.leerMovimientoHistorico (rowIndex);
switch (columnIndex) {
case 0: return sdf.format (m.fecha);
case 1: switch (m.tipo) {
case 'I': return "ingreso";
case 'R': return "reintegro";
}
case 2: return new Float (m.importe);
case 3: return new Float (m.saldo);
}
return ""; // Aquí no se debería llegar !
}
}

Esta clase usa dos operaciones de la clase Cuenta no existentes en la versión inicial 
que vimos en el tema 2: int numMovimientosHistorico() y Movimiento 
leerMovimientoHistorico(int nm)
Captura de eventos
Programación en 
GUIs

Queda un fleco pendiente. Si terminamos la aplicación mediante el botón “Salir” la 
cuenta actual queda salvada en disco automáticamente antes de salir. Sin embargo, si 
utilizamos el botón de cerrar la ventana la aplicación se cierra directamente sin salvar la 
cuenta
Para evitar esto vamos a capturar los eventos relacionados con la ventana mediante 
un WindowListener. En lugar de implementar toda la inferfaz, extendemos la clase 
WindowAdapter y redefinimos únicamente la operación que captura el evento de cierre 
de la ventana. Esto nos va a obligar a utilizar una clase interior (¿por qué?)

// Estamos en el interior de la clase FAppBanco

class FAppBancoWindowListener extends WindowAdapter {


public void windowClosing(WindowEvent e) {
terminarAplicacion();
}
}

// Estamos en el interior del constructor de la clase FAppBanco

// Anulamos esta instrucción


// setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
// Y la sustituimos por una conexión al listener
addWindowListener(new FAppBancoWindowListener());

Captura de eventos
Programación en 
GUIs

Con esto nuestra aplicación ya es utilizable. Podemos cargar una cuenta existente en 
disco o crear una nueva

Captura de eventos
Programación en 
GUIs

Cuadros de diálogo
Los cuadros de diálogo son ventanas con una función 
específica
Notificar al usuario un error, advertencia o consejo
Pedir confirmación sobre una operación determinada que se va a realizar
Obtener la información necesaria para la realización de una operación determinada
Una capacidad especial de los cuadros de diálogo es la 
de bloquear la aplicación de forma que el usuario no 
pueda seguir trabajando hasta que se atiende a su 
petición. Este tipo de cuadros de diálogo se denominan 
modales
El uso más frecuente de los cuadros de diálogo es el de 
notificación y confirmación. Para este fin Swing cuenta 
con cuadros de diálogo predefinidos
Cuadros de diálogo
Programación en 
GUIs

Para realizar una notificación utilizaremos la siguiente 
operación: JOptionPane.showDialog(<frame o diálogo 
padre>, <mensaje>, <título>, <tipo>)
El tipo de mensaje puede ser de los siguientes tipos:
ERROR_MESSAGE
INFORMATION_MESSAGE
WARNING_MESSAGE
QUESTION_MESSAGE
PLAIN_MESSAGE
Esto crea lo que se conoce como message box o 
cuadro de mensaje modal, con un icono en función del 
tipo

Cuadros de diálogo
Programación en 
GUIs

Para pedir una confirmación utilizaremos la siguiente 
operación: JOptionPane.showConfirmDialog(<frame o 
diálogo padre>, <mensaje>, <título>, <opciones>, 
<tipo>)
Los parámetros son similares. El campo de opciones 
puede tomar los valores
YES_NO_OPTION
YES_NO_CANCEL_OPTION
El valor retornado por esta operación es un entero que 
indica el botón pulsado:
YES_OPTION
NO_OPTION
CANCEL_OPTION
CLOSED_OPTION

Cuadros de diálogo
Programación en 
GUIs

Hasta ahora en nuestra aplicación los mensajes de error se lanzaban a la consola. Es 
hora de cambiar todos estos mensajes por cuadros de diálogo. También vamos a 
introducir un cuadro de confirmación cuando se intenta crear una cuenta ya existente
public void actionPerformed(ActionEvent e) {
if (e.getSource() == bc) {
long codigo = comprobarCodigo();
if (codigo == -1)
return;

float interes = comprobarInteres();


if (interes == -1)
return;

salvarCuentaActual();

if (existeCuenta(codigo))
if (JOptionPane.showConfirmDialog(this,
"Ya existe una cuenta con ese código. ¿Desea sobreescribirla?",
"Atención", JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE) != JOptionPane.YES_OPTION)
return;

c = new Cuenta(codigo, tft.getText (), interes);


tfs.setText("0.0");
bo.setEnabled(true);
}

// Sigue la implementación del resto de la operacion...

Cuadros de diálogo
Programación en 
GUIs

private long comprobarCodigo() {


long codigo;

try {
codigo = Long.parseLong(tfc.getText ());
if (codigo < 0)
throw new NumberFormatException();
}
catch (NumberFormatException nfe) {
JOptionPane.showMessageDialog(this, "Código de cuenta incorrecto",
"Error", JOptionPane.ERROR_MESSAGE);
return -1;
}
return codigo;
}

private float comprobarInteres() {


float interes;
try {
interes = Float.parseFloat(tfi.getText ());
if (interes < 0 || interes > 100)
throw new NumberFormatException();
}
catch (NumberFormatException nfe) {
JOptionPane.showMessageDialog(this,
"Interés incorrecto. Debe ser un valor real entre 0 y 100",
"Error", JOptionPane.ERROR_MESSAGE);
return -1;
}
return interes;
}

Cuadros de diálogo
Programación en 
GUIs

La forma más común de realizar una petición de 
información por parte del usuario es construir un cuadro 
de diálogo a medida, normalmente de tipo modal
La clase que representa un cuadro de diálogo genérico 
es JDialog. Al igual que en el caso de los frames, 
dependiendo de la complejidad del cuadro que 
necesitemos podremos construirlo directamente o 
utilizar extensión para construir un cuadro de diálogo 
personalizado
El constructor de JDialog es el siguiente: 
JDialog(<frame o dialogo padre>, <título>, <¿modal?>)

Cuadros de diálogo
Programación en 
GUIs

Cuando el usuario pulse el botón “Operación” vamos a presentar un cuadro de diálogo 
que pida el importe y el tipo de operación a realizar. Vamos a construir este cuadro de 
diálogo como una clase nueva hija de JDialog denominada DOperacion
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class DOperacion extends JDialog implements ActionListener {


JTextField tfi;
JRadioButton rbi, rbr;
JButton br, bc;

// Importe de la operación
float importe;
// Este atributo tendrá valor true si los datos introducidos son correctos
// y el usuario pulsa el botón “Realizar”
boolean operar;

public DOperacion(JFrame f) {
super (f, "Realizar operación", true);

JPanel p = new JPanel();


p.setLayout (new FlowLayout());
JLabel l = new JLabel("Importe");
p.add(l);

tfi = new JTextField(8);


p.add (tfi);

JPanel pto = new JPanel();


pto.setLayout (new FlowLayout());
Cuadros de diálogo
Programación en 
GUIs

Para que los radio buttons de “ingreso” y “reintegro” sean autoexcluyentes deben ser 
agrupados utilizando un ButtonGroup

rbi = new JRadioButton("Ingreso", true);


rbr = new JRadioButton("Reintegro");

ButtonGroup bg = new ButtonGroup();


bg.add(rbi); // Añadir los dos botones al grupo
bg.add(rbr);

pto.add(rbi);
pto.add(rbr);

JPanel pb = new JPanel();


pb.add(br = new JButton("Realizar"));
pb.add(bc = new JButton("Cancelar"));

setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));


add(p);
add(pto);
add(pb);
pack();

// Capturar la pulsación de los dos botones


bc.addActionListener(this);
br.addActionListener(this);

operar = false;
importe = 0;
}

Cuadros de diálogo
Programación en 
GUIs

Capturamos la pulsación de los dos botones. Al pulsar “Realizar” comprobaremos si el 
importe es correcto y en caso afirmativo daremos el visto bueno estableciendo el 
atributo operar a true
Para poder obtener toda la información desde el frame principal hemos introducido 
algunas operaciones adicionales

public void actionPerformed(ActionEvent e) {


if (e.getSource () == br) {
try {
importe = Float.parseFloat (tfi.getText ());
operar = true;
hide ();
}
catch (NumberFormatException nfe) {
JOptionPane.showMessageDialog (getContentPane (), "Importe incorrecto",
"Error", JOptionPane.ERROR_MESSAGE);
}
}

if (e.getSource () == bc)
hide ();
}

public float leerImporte () { return importe; }


public boolean esIngreso () { return rbi.isSelected (); }
public boolean esReintegro () { return rbr.isSelected (); }
public boolean realizarOperacion () { return operar; }
}

Cuadros de diálogo
Programación en 
GUIs

Sólo falta lanzar el cuadro de diálogo cuando se pulse el botón de “Operación”. Para 
ello introduciremos el siguiente código en la operación actionPerformed() de FAppBanco
// Estamos en actionPerformed de la clase FAppBanco

if (e.getSource() == bo) {
DOperacion d = new DOperacion(this); // Construir diálogo y mostrarlo
d.setVisible(true);

// ¿Se ha pulsado el botón de realizar operación?


if (d.realizarOperacion()) {
if (d.esIngreso())
c.ingreso(d.leerImporte());
else
c.reintegro(d.leerImporte());
// Cambiar valor en el text field de saldo
tfs.setText(new Float(c.leerSaldo()).toString());
// Indicar a la tabla que hemos añadido una fila, para que se actualice
im.fireTableRowsInserted(c.numMovimientosHistorico() - 1,
c.numMovimientosHistorico() - 1);
}
}
}

Cuadros de diálogo
Programación en 
GUIs

Teclas rápidas
Los usuarios que utilizan habitualmente una aplicación 
suelen requerir ciertas rápidas para agilizar su uso
Normalmente una tecla rápida suele ser una 
combinación del tipo ALT+tecla
Además, debe ayudarse al usuario a identificar estas 
teclas rápidas marcando la tecla en el componente en 
cuestión

Teclas rápidas
Programación en 
GUIs

En los componentes que tienen asociada una etiqueta, 
como botones, opciones de menús, etc. la tecla rápida 
se establece mediante 
componente.setMnemonic(<tecla>)
Las teclas vienen identificadas mediante una serie de 
códigos en la clase KeyEvent. Consultar la referencia de 
esta clase para obtener la lista completa de códigos
Las teclas normales tienen asociadas códigos sencillos. 
Por ejemplo la tecla K se codifica como VK_K
Si la tecla indicada tiene un carácter asociado y éste 
aparece en la etiqueta del componente, Swing se 
encarga de resaltarlo automáticamente

Teclas rápidas
Programación en 
GUIs

Existen componentes que no tienen ninguna etiqueta 
(p. e. JTextField). Si asociamos teclas a estos 
componentes, el usuario no tiene forma de saber cuáles 
son
Sin embargo, estos componentes suelen tener un 
JLabel para su identificación. Podemos asociar la tecla 
al JLabel de la siguiente manera:
label.setLabelFor(textfield)
label.setDisplayedMnemonic(<tecla>)
De esta forma el JLabel muestra la tecla rápida, pero 
realmente es el editor el que la recibe
Resulta obvio decir que no deben repetirse las teclas 
rápidas dentro de un frame o dialog
Teclas rápidas
Programación en 
GUIs

La tecla TAB funciona también automáticamente para  
desplazar el foco de un componente a otro. El orden de 
visita de los componentes viene dado por el orden de 
inserción de éstos en el panel
En los cuadros de diálogo es frecuente que exista un 
botón por defecto, que se activa pulsando la tecla 
RETURN. Este botón aparece remarcado sobre el resto

El botón por defecto del cuadro de diálogo puede 
indicarse de la siguiente manera: 
dialogo.getRootPane().setDefaultButton(boton)

Teclas rápidas
Programación en 
GUIs

Teniendo en cuenta lo anterior, añadir las teclas rápidas a nuestra aplicación es una 
cuestión rutinaria. Mostramos aquí parte del código modificado

public FAppBanco() {
super("Gestión de Cuentas Bancarias");
JLabel l;
// Etiquetas y editores
JPanel pc = new JPanel();
pc.setLayout(new FlowLayout(FlowLayout.LEFT));
pc.add(l = new JLabel("Código"));
pc.add(tfc = new JTextField(8));
l.setLabelFor(tfc);
l.setDisplayedMnemonic(KeyEvent.VK_C);

JPanel pt = new JPanel();


pt.setLayout(new FlowLayout(FlowLayout.LEFT));
pt.add(l = new JLabel("Titular"));
pt.add(tft = new JTextField(30));
l.setLabelFor(tft);
l.setDisplayedMnemonic(KeyEvent.VK_T);

// Sigue el código aquí...

// Botones
JPanel pb = new JPanel(new FlowLayout(FlowLayout.CENTER));
pb.add(bc = new JButton("Crear"));
bc.setMnemonic(KeyEvent.VK_R);
pb.add(bb = new JButton("Buscar"));
bb.setMnemonic(KeyEvent.VK_B);
pb.add(bo = new JButton("Operación"));
bo.setMnemonic(KeyEvent.VK_O);

// Etc, etc... Teclas rápidas


Programación en 
GUIs

Los “looks” de Swing
Para terminar con nuestro ejemplo y el tema dedicado a programación en GUIs 
podemos probar distintos “looks” para nuestra aplicación

import javax.swing.UIManager;
import javax.swing.JFrame;
import javax.swing.JDialog;

public class AppBanco {

public AppBanco() {
}

public static void main(String[] args) {


try {
UIManager.setLookAndFeel(com.sun.java.swing.plaf.metal.MetalLookAndFeel");
//UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
//UIManager.setLookAndFeel(“com.sun.java.swing.plaf.motif.MotifLookAndFeel");
}
catch (Exception e) {}

JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);

FAppBanco f = new FAppBanco();


}
}

Los ”looks” de Swing
Programación en 
GUIs

Look “Metal” (por defecto en Java 1.4)

Look “GTK”

Look “Motif” Los ”looks” de Swing

S-ar putea să vă placă și