Documente Academic
Documente Profesional
Documente Cultură
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 PersonaOrdenador)
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 Draganddrop, 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 ObjetiveC, un
lenguaje OOP
Evolución histórica
Programación en
GUIs
XWindow
El sistema XWindow fue desarrollado en el MIT en 1984, apareciendo la
primera versión comercial en 1986. XWindow 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 XWindow era necesario un gestor de ventanas, que
era el que proporcionaba el lookandfeel 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 XWindow 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
XWindow
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 MSDOS
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
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 minimizarmaximizarcerrar 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
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 PersonaOrdenador 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;
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.*;
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;
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.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.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
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.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
f.setLayout(null);
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");
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 FAppBanco() {
super("Gestión de Cuentas Bancarias");
psi.add(new JLabel("Interés"));
psi.add(tfi = new JTextField(4));
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
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í...
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
A continuación, implementaremos la única operación de esta interfaz y algunas
operaciones auxiliares
if (existeCuenta(codigo)) {
System.out.println(“La cuenta ya existe !”);
return;
}
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;
}
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...
// Continua el constructor...
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...
// Continua el contructor...
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;
salvarCuentaActual ();
if (existeCuenta (codigo)) {
System.out.println ("Ya existe una cuenta con ese código");
return;
}
try {
c = new Cuenta (codigo); // Cargar la cuenta
if (e.getSource () == bs)
terminarAplicacion ();
}
Vamos a incluir en la operacion actionPerformed() de FAppBanco el código de
procesamiento de los botones “Crear”, “Buscar” y “Salir”
public InfoMovimientos () {
super ();
Captura de eventos
Programación en
GUIs
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é?)
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;
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;
Cuadros de diálogo
Programación en
GUIs
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;
}
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.*;
// 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);
Para que los radio buttons de “ingreso” y “reintegro” sean autoexcluyentes deben ser
agrupados utilizando un ButtonGroup
pto.add(rbi);
pto.add(rbr);
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
if (e.getSource () == bc)
hide ();
}
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);
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);
// 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);
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 AppBanco() {
}
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);
Los ”looks” de Swing
Programación en
GUIs
Look “Metal” (por defecto en Java 1.4)
Look “GTK”
Look “Motif” Los ”looks” de Swing