You are on page 1of 21

Politécnico Grancolombiano

Herramientas de
Desarrollo
Interfaces gráficas de usuario: Java Swing
Diego A. Cabra

10
Herramientas de desarrollo

INTERFACES GRÁFICAS DE USUARIO:


JAVA SWING

La mayoría de los programas desarrollados actualmente, se comunican con el


usuario por medio de elementos como botones, menús y ventanas. Estos
elementos componen la denominada interfaz gráfica de usuario o GUI por sus
siglas en ingles. Estas interfaces componen la parte visible de las aplicaciones por
tanto es un componente fundamental del desarrollo que no debe tratarse
superficialmente. La percepción de un usuario hacia el sistema desarrollado,
depende en gran medida de la interfaz que este utiliza para interactuar con la
aplicación. De poco sirve una aplicación correctamente modelada, con los mejores
algoritmos y diseños, eficiente y robusta, si el usuario final no puede acceder a
estas características por culpa de una interfaz mediocremente desarrollada.

De igual forma una interfaz de usuario demasiado compleja, así provea la


funcionalidad necesaria, concentrará el esfuerzo del usuario en comprender la
interfaz y no en su propio trabajo, o consumirá su tiempo leyendo manuales,
llenando formularios y presionando botones. La interfaz debe ser sencilla, intuitiva
y eficaz, propiedades que pueden lograrse más fácilmente por medio de ventanas,
botones, iconos, etc, que con las clásicas aplicaciones de consola.

Fig 1. Interfaz Swing


Actualmente las interfaces gráficas de usuario en su gran mayoría se basan en un
sistema de ventanas, las cuales contienen diferentes tipos de componentes que se
adaptan a distintas necesidades. En términos generales podríamos clasificar los
elementos de una interfaz gráfica en las siguientes categorías:

ELEMENTOS DE UNA GUI


VENTANAS
Las ventanas, marcos o frames, son los elementos encargados de contener a
otros en el nivel más superior, es decir una ventana no puede estar contenida en
ningún otro elemento. Estos elementos interactúan directamente con la plataforma
en la que se ejecutan, pudiendo de esta forma moverlos libremente y
transformarlos según las restricciones.

Estos contenedores de nivel superior, se pueden clasificar también en:

Ventanas de aplicación. Son los contenedores principales de la aplicación. Por


lo general al cerrar este componente la aplicación termina. Permite el acceso a
toda la funcionalidad de la aplicación.
Diálogos. Los cuadros de diálogo son un tipo especial de ventana, diseñada
para que sea visible generalmente durante un breve periodo. Se usan para
informar o pedirle información al usuario. Los diálogos están relacionados con la
ventana de la aplicación, si esta se cierra, todos los diálogos se cierran, o si esta
se minimiza los diálogos también lo hacen. Un diálogo muy común en las
aplicaciones es aquel que aparece cuando se desea cerrar una aplicación,
preguntando si se desea guardar algún tipo de información. Este tipo de diálogo
no permite ninguna interacción con la aplicación hasta que el usuario responda el
requerimiento o confirmación. A este tipo de diálogos se les conoce como
modales. De igual forma un diálogo no modal es aquel que se despliega pero no
interrumpe ni evita la interacción con otras ventanas de la aplicación. Los cuadros
de diálogo son independientes de la ventana de la aplicación, por lo que estos
también se pueden mover libremente aún fuera de los límites de la ventana
principal.
Ventanas sin marco. Este tipo de ventanas no contiene ningún tipo de control
asociado con el sistema, como minimizar, maximizar o cerrar. Es común su uso en
pantallas de bienvenida o carga de las aplicaciones.
COMPONENTES
Todos los elementos de una interfaz gráfica son tratados como componentes de
está. Entre estos se clasifican entonces los botones, las barras de
desplazamiento, listas, tablas, y demás. Estos componentes se pueden clasificar
en:

Contenedores. Como se puede intuir, un contenedor es un componente que


puede organizar en su interior otros componentes. Se asocian directamente con
los paneles, aunque no solamente estos son contenedores. Dependiendo de la
necesidad, los contenedores pueden adaptarse para mostrar su contenido de
diferentes formas, como con barras de desplazamiento, pestañas, divisiones, etc.
Una ventana interna se puede clasificar como contenedor, pero no de nivel
superior, pues estas están contenidas dentro de otros contenedores. Sirven para
desplegar herramientas o información que puede ser ocultada o redimensionada
dentro de la aplicación, pero que a diferencia de los diálogos, no puede ser movida
más allá de los límites de la ventana de la aplicación.
Controles. Los controles son componentes con los que el usuario puede
interactuar para suministrar información a la aplicación mediante interacciones con
el mouse o el teclado. Clasifican aquí los botones, deslizadores, listas
desplegables, cajas de verificación, etc.
De Texto. Los componentes de texto permiten la manipulación de datos
recibidos por el teclado, tales como los campos de texto o las áreas de texto.

MENÚS
Los menús son un conjunto de botones organizados de forma generalmente
vertical. Estos botones pueden a su vez desplegar otros menús, para dar un
comportamiento de cascada a la navegación por este tipo de elementos.
Generalmente se organizan en un segmento de la parte superior de la ventana
conocido como barra de menú. Esta barra contiene un conjunto de botones
organizados horizontalmente que al presionarlos despliegan sus menús
asociados.

TOOLTIP
Un tooltip es un breve mensaje asociado a un componente, que brinda una
pequeña descripción o ayuda acerca de este. Los tooltips se hacen visibles
cuando el cursor del mouse se posa sobre un componente durante un breve
periodo de tiempo.
ADMINISTRACIÓN DE UNA GUI
Todos los componentes de una interfaz están relacionados de alguna forma con la
aplicación, ya sea directamente, o por medio de su relación con otros
componentes. La funcionalidad de la interfaz depende entonces en gran parte de
cómo se gestionen todas estas relaciones.

Dado que hay una relación de contenedor-componente, se crean relaciones


jerárquicas entre los elementos de la interfaz. La ventana de la aplicación esta en
el nivel superior, y los demás componentes harán parte de ella o algún otro
contenedor. Como algunos contenedores son componentes a su vez, puede haber
varios niveles de jerarquía.

DISTRIBUCIÓN
Los componentes deben tener un orden dentro del contenedor en el que se alojan.
Esta distribución puede ser determinada por el desarrollador indicando las
coordenadas de cada componente, o usando estándares de distribución ya
definidos, para solo preocuparse por adicionar el componente al contenedor sin
pensar en las coordenadas exactas de su ubicación.

FOCO
Otro aspecto a tener en cuenta en la administración de una interfaz, es el foco de
los componentes. Cuando un usuario presiona por ejemplo la tecla enter, a que
componente afectará si hay varios en la misma ventana. Esto lo determina el foco
el cual solo le pertenece a un componente y se puede trasladar de uno a otro por
medio del ratón o del teclado con la tecla TAB.

EVENTOS
Luego de diseñada la interfaz, definidos sus componentes, su distribución y
política de transmisión del foco, la interfaz puede lanzarse como un elemento
independiente de la aplicación. El problema claro está, es que no tendría
funcionalidad alguna, y las interacciones del usuario no desencadenarán ninguna
acción. La interfaz gráfica debe conectarse con la aplicación por medio de las
respuestas que debe dar a las interacciones del usuario con los componentes.

La forma como responde cada componente a las interacciones del usuario, está
determinada por un sistema de delegación de responsabilidades en donde el
principal actor es el evento. Cuando un usuario interactúa con un componente, por
ejemplo presiona un botón, se genera un evento que representa esta acción. Este
evento debe ser comunicado a otro actor del sistema llamado controlador. Es este
quien finalmente determina qué hacer cuando reciba un evento. De esta forma, los
componentes actúan como los objetos fuente de los eventos, son estos quienes
liberan los eventos cuando hay interacciones. Los mismos objetos fuente tienen
una lista de los objetos que pueden manejar sus eventos, los controladores,
depende del tipo de evento, se asocia un tipo de controlador. Según el tipo de
evento generado, el componente le informa a su controlador que se debe manejar
un evento. El controlador recibe este evento y efectúa el método correspondiente
para responder el llamado. Más adelante detallaremos este proceso
concentrándonos en el lenguaje Java.

JAVA FOUNDATION CLASSES


El lenguaje de programación Java, provee un conjunto de clases agrupado bajo la
biblioteca denominada JFC (Java Foundation Classes), que brinda soporte a
aplicaciones que utilicen interfaces gráficas de usuario. JFC define las siguientes
API:

Swing, es un conjunto de clases que definen componentes gráficos escritos en


Java, trabajando de forma transparente sobre cualquier plataforma.
AWT (Abstract Window Toolkit), este grupo de componentes están diseñados
para trabajar igualmente en cualquier plataforma, pero a diferencia de Swing,
utiliza en vez de Java, código nativo de la plataforma sobre la que se ejecuta, es
decir le pide al sistema operativo que cargue los componentes.
Accesibilidad, JFC provee clases que soportan aplicaciones para usuarios que
tienen limitaciones para utilizar las interfaces gráficas normales.
Java 2D, permite incorporar gráficos 2D sobre componentes de los programas.
Soporte “drag and drop”, permite la característica de arrastrar y soltar para
comunicar datos entre aplicaciones.

Las interfaces gráficas de usuario en Java se implementaron en un principio sobre


AWT, el problema era que si querían que funcionara en todas las plataformas, solo
podían tomar las características comunes a todas ellas para poder incluirlas en el
API. En ocasiones las aplicaciones no resultaban totalmente multiplataforma, pues
había que hacer ajustes, esto rompía con uno de los principios de Java. A partir de
esta problemática surgió Swing; este API está escrito en Java, y no hace uso de
código nativo para desplegar sus componentes, todos son desplegados por la
máquina virtual, lo que hace de estas aplicaciones totalmente portables. Al ser
estos componentes independientes de la plataforma, las GUI desarrolladas en
Java lucen igual en cualquier plataforma. Para personalizar estas interfaces se
pueden usar diferentes “look & feel” que permiten adaptar los componentes GUI
con diferentes visualizaciones para que luzcan según la plataforma.
SWING
Swing es lo que se conoce como un GUI toolkit o widget toolkit, un conjunto de
herramientas de software junto con una interfaz de programación de aplicaciones
(API) que permiten el desarrollo de interfaces gráficas de usuario (GUI). Swing es
el widget toolkit de Java, sus herramientas son pequeños programas que actúan
como elementos básicos de construcción de una GUI, los llamados widgets. Estos
widgets son componentes de software que ya vienen construidos dentro de Swing,
y que el desarrollador de la interfaz solo debe conocer cómo integrarlos sin
preocuparse por su implementación interna o de saber cómo y porque funcionan.
Los widgets en Swing son modelados en clases, en donde se abstrae los atributos
y comportamientos de cada widget en específico. Por ejemplo, un botón se
modela dentro de la clase JButton, la cual tiene atributos como el texto del botón,
el color, el tamaño, y tiene métodos para poder deshabilitarlo, ocultarlo, etc.

Todo el conjunto de clases se encuentra dentro del paquete javax.swing, aquí se


definen todos los componentes como clases. Si se desea utilizar un botón en una
aplicación, basta con instanciar un objeto de la clase adecuada y adicionarlo a la
ventana que lo necesita. Veamos una descripción general de los componentes
que define esta interfaz de aplicación y de la estructura de trabajo para escribir
GUI por medio de estos y controlando eventos para dar respuesta a las
interacciones. El detalle de cada clase se extiende más allá del alcance de este
documento, ya que el estudio concreto de las características de un componente
depende del uso que se le vaya a dar. Trabajar con Swing involucra una gran
cantidad de clases e interfaces, con gran cantidad de atributos y comportamientos,
que pueden ser fácilmente consultados cuando se demanden. Entre los
contenidos semanales del modulo, encontrarán un OVA que da una visión general
con cierto nivel de detalle, de los componentes de Swing, su utilidad,
comportamiento e implementación.

ELEMENTOS DE SWING
Como anteriormente se mencionaba, en Swing cada componente esta modelado
dentro una clase, cada clase define como atributos todas aquellas características
de dicho componente, como color y tamaño. Los componentes están destinados a
hacer parte de un contenedor que también está modelado en clases del API. De
forma general, un contenedor recibe un componente para desplegarlo, haciéndolo
visible al usuario. Java hace uso de la herencia para expresar estas relaciones de
una forma más clara y coherente. Sin el uso de la herencia en este diseño los
contenedores tendrían que tener métodos diferentes para responder mensajes del
tipo: inserte un botón, inserte un campo de texto, inserte un panel, etc.
Todos los contenedores parten de la implementación de AWT para estos
elementos, modelados en la clase Container. La clase Container define los
miembros generales que definen a su vez a las ventanas, por esto existe la clase
Window que hereda de Container. Window define el concepto general de los
contenedores de nivel superior, a partir de esta clase nacen las implementaciones
de Swing para este tipo de elementos. Las ventanas de aplicación están
modeladas por la clase JFrame, los diálogos en la clase JDialog y las ventanas sin
marco por la clase JWindow. Las clases de Swing se diferencian por la J que se
antepone a los nombres. En estos contenedores de nivel superior inicia la
jerarquía de componentes de la interfaz gráfica, pues sobre ellos se insertan los
componentes que se requieran. Un componente se define dentro de Java en su
concepto más general como un objeto de la clase JComponent. Todos los
componentes específicos heredan de esta clase, y de esta forma adquieren la
propiedad de poder ser insertados en un contenedor. En la siguiente figura
podemos ver de forma general esta jerarquía y algunas clases de componentes.

Fig 2. Jerarquía de clases Swing


JFRAME
Es por medio de la herencia y la composición que finalmente se podrá construir
una interfaz gráfica de usuario. La clase JFrame define una ventana vacía pero
con la funcionalidad básica ya implementada de los botones de cerrar, minimizar y
maximizar. También tiene un menú de control que se puede acceder con un clic
sobre el ícono de la aplicación en la esquina superior izquierda.

Fig 3. JFrame

Un JFrame administra los componentes que sobre él se van a agregar por medio
de una serie de contenedores auxiliares. El que finalmente va a contener es un
JPanel conocido como Content Pane, el panel de contenido. Estos paneles de
contenido vienen construidos desde la Clase JFrame, y está define métodos para
insertar componentes sobre el panel.

1
Fig 4. Paneles de contenido

Normalmente la tarea entonces a la hora de implementar una interfaz gráfica de


usuario, consiste en crear un tipo especial de ventana que contenga los
componentes y comportamientos deseados. Para no volver a definir aspectos
1
Imagen extraída: Oracle Corporation. The Java SE Tutorial [En línea]. <
http://download.oracle.com/javase/tutorial/uiswing/>. [Consultado 25/05/2010]
básicos como los botones de control, el panel de contenido y la barra de titulo, la
mejor opción es que nuestra nueva clase herede todas las características ya
definidas en JFrame.

Al heredar de JFrame, están disponibles en nuestra clase los métodos y atributos


necesarios para empezar a construir la aplicación. Para insertar un componente,
basta con declarar un objeto de la clase apropiada como atributo de la clase.
Luego de instanciarlo de forma adecuada, se puede llamar al método de JFrame
que inserta componentes en el Content Pane. Estos componentes se distribuyen
en el panel de acuerdo al patrón de distribución elegido.

LAYOUT MANAGER
La distribución de los componentes sobre un contenedor está determinada por un
conjunto de clases llamadas Layout Managers, de forma simplificada Layout. Los
layout definen un patrón de distribución sobre el contenedor al que se apliquen. Al
definir el layout todos los componentes que se inserten se acomodarán de
acuerdo al patrón de distribución automáticamente. Si se desea, se puede optar
por no utilizar ningún Layout Manager, en este caso la distribución de cada
componente es responsabilidad total del desarrollador, quien tendría que definir en
términos de coordenadas la posición de cada componente que inserte al
contenedor. En java se definen los siguientes Layout Managers:

BorderLayout: los paneles de contenido de los JFrame siempre vienen


configurados por defecto con este layout. La forma de distribución se basa en la
división del área del contenedor en cinco zonas diferentes: top, bottom, left, right y
center. En cada una de estas zonas se puede insertar un solo componente
directamente, pero este componente podría ser un JPanel, lo que permitiría
insertar más componentes en una zona de distribución. 2

Fig 5. Distribución BorderLayout

2
Ibíd.
BoxLayout: esta distribución ubica los componentes en una fila o columna
sencilla, dependiendo de los tamaños de cada componente y su alineación.

3
Fig 6. Distribución BoxLayout

CardLayout: un CardLayout permite crear áreas que contienen componentes


diferentes en ciertos momentos. Los componentes que se despliegan son
controlados por una lista desplegable de la clase JComboBox. Dependiendo de la
selección sobre esta lista, se despliegan diferentes componentes.

4
Fig 7. Distribución CardLayout

FlowLayout: Esta distribución viene configurada por defecto en todos los


JPanel. Distribuye los componentes en una fila sencilla, si el contenedor no es
suficientemente ancho para albergar todos los componentes entonces se creará
una nueva fila cada vez que sea necesario.

3
Ibíd.
4
Ibíd.
5
Fig 8. Distribución FlowLayout

GridBagLayout: administra una distribución flexible, organizando a los


componentes en una grilla de celdas, en donde se puede ubicar un componente,
aunque también se permite que un componente utilice más de una celda. Las filas
pueden tener diferentes alturas, y las columnas pueden tener diferentes anchos.

6
Fig 9.Distribución GridBagLayout

GridLayout: el GridLayout ubica los componentes en una grilla de celdas de


igual tamaño según la cantidad de filas y columnas configuradas.

6
Fig 10. GridLayout

5
Ibíd.
6
Ibíd.
JCOMPONENT
Es la superclase de todos los componentes que pueden insertarse en un
contenedor. Define atributos generales como lo son el color, el tamaño o la
posición. Todos los componentes de Swing heredan de esta clase, excepto los
contenedores de primer nivel (JFrame, JDialog y JWindow), que no se pueden
insertar en ningún otro contenedor. Estos componentes se conocen también como
widgets, ya que están listos para usarse dentro de un contenedor, lo único
necesario es instanciar el objeto de la clase deseada e insertarlo al contenedor
que lo hará visible. En el siguiente diagrama se puede apreciar de forma más
detallada las clases que hacen parte Swing, los componentes se pueden apreciar
heredando de JComponent, las clases en color son la base AWT de Swing. Una
descripción detallada de cada clase la podrá encontrar en el Ova de Swing de esta
semana. También encontrará un video diapositiva con un ejemplo práctico de la
construcción de una GUI sencilla.

7
Fig 11. Componentes Swing

7
ALLEN I, Holub. Java Swing Classes [En línea]. http://www.holub.com/goodies/java.swing.html
[Consultado 15/12/2010]
EVENTOS
Las clases involucradas en el manejo de eventos de una interfaz gráfica Java, se
encuentran en el paquete java.awt.event. Allí se pueden encontrar los eventos que
en un momento determinado puede generar un componente. Dependiendo del tipo
de interacción el componente liberará diferentes tipos de eventos.

Clases de eventos comunes


Es un tipo de evento que se libera al interactuar con ciertos
ActionEvent tipos de componentes, por ejemplo cuando un botón es
presionado se crea un ActionEvent.
Objetos de este tipo se lanzan desde componentes ajustables.
El más común de estos es el que se libera cuando en un panel
AdjustmentEvent
con barras de desplazamiento se realiza precisamente un
desplazamiento.
Estos eventos indican cuando un componente se ha movido,
ComponentEvent
cambiado de tamaño o su visibilidad.
Cuando los componentes de un contenedor cambian, por
ContainerEvent
ejemplo al agregar uno nuevo, se lanza un evento de este tipo.
Este evento indica cuando un componente ha ganado o
FocusEvent
perdido el foco de la ventana.
Es la clase padre de todos los eventos que se generan cuando
InputEvent
hay una entrada de datos por parte del usuario.
Un evento que indica cuando un ítem de algún componente ha
ItemEvent
sido seleccionado o deseleccionado, por ejemplo en una lista.
Indica cuando un usuario a digitado algo en el teclado. El
KeyEvent evento es liberado por el componente que tenía el foco en el
momento en que el usuario presiona la tecla.
Estos eventos indican que ha ocurrido alguna acción con el
MouseEvent
mouse.
Se libera cuando se ha usado la rueda del botón sobre algún
MouseWheelEvent
componente.
TextEvent Indica cuando un objeto de texto ha cambiado
Indica cuando una ventana ha cambiado su estado, por
WindowEvent
ejemplo al minimizarse, cerrarse, abrirse, etc.
Tabla 1. Clase de eventos comunes

Cuando se produce un evento, el objeto fuente de este evento, es decir el


componente sobre el que se realizó la interacción delega la responsabilidad de
tratar a este evento a un objeto de una clase especial conocido como controlador
o manejador de eventos. No cualquier objeto puede llegar a ser un controlador,
puesto que los componentes se comunican con métodos específicos de estos
objetos cuando se produce un evento. Los métodos que los componentes conocen
están definidos en un conjunto de interfaces que definen cual debe ser la
estructura de una clase que pretenda producir objetos para controlar eventos.

Existen interfaces para cada tipo de evento, en Java se conocen como Listeners,
oyentes, ya que los objetos de las clases que implementen estas interfaces,
estarán todo el tiempo a la escucha de algún evento para poder manejarlo
adecuadamente. Si se quiere crear un objeto que controle los eventos que se
generan al presionar un botón entonces abría primero que averiguar qué tipo de
evento se libera ante esta acción, en este caso un ActionEvent. Conocido este
aspecto se sabe que la clase del objeto controlador debe tener los métodos que el
botón conoce y utilizará cuando se produzca un AcionEvent, por esto se debe
entonces escribir una clase que implemente la interfaz ActionListener e
implementar los métodos que esta tenga, en este caso solo uno llamado
actionPerformed.

Cuando se produce un evento, el objeto fuente determina el tipo de este, y llama al


método adecuado de un controlador para que este decida qué hacer. Entonces el
objeto fuente debe tener referencias a objetos controlador a los cuales enviarles
estos mensajes. Todos los JComponent declaran una lista de controladores o
como ellos definen Event Listeners, dependiendo el tipo de cada controlador el
componente sabe a cuál de ellos enviar el mensaje. Este mensaje lleva adjunto
como argumento el evento generado instancia de la clase Event específica. Por
medio de este objeto el controlador puede obtener información acerca de la
interacción que originó el evento, por ejemplo saber que tecla se presionó en el
teclado, o que botón del mouse se presionó.

Todo esto se hace de forma transparente incluso para el programador. Este,


únicamente se debe preocupar por los siguientes aspectos:

Determinar el componente que será fuente de los eventos, por ejemplo un


JButton.
Escribir la clase de los controladores según el tipo de evento que se quiere
manejar, para el caso del botón por ejemplo, la clase debe implementar
ActionListener.
Indicarle al componente que objetos controlarán los eventos. Este proceso se
conoce como registro. Se debe registrar el controlador sobre el componente. El
registro depende del evento que se quiera manejar, por ejemplo para registrar el
controlador ActionListener sobre un botón se debe llamar al método
addActionListener, que recibe un objeto de alguna clase que implemente la
interfaz correspondiente.

Cada componente puede registrar diferentes tipos de controladores dependiendo


del tipo de eventos que pueden generar. Todos los componentes de Swing
pueden registrar los siguientes controladores:

Component listener
Escucha y controla eventos de tipo ComponentEvent, que resultan al cambiar el
tamaño, posición visibilidad de un componente.

Focus listener
Escucha esperando eventos liberados cuando se gana o pierde el foco en un
componente.

Key listener
Controla eventos generados al presionar alguna tecla en el teclado.

Mouse listener
Controla las acciones que se pueden realizar con un mouse sobre un componente,
como movimientos y clics.

Mouse-motion listener
Controla cambios en la posición del cursor del mouse sobre un componente.

Mouse-wheel listener
Controla movimientos de la rueda del mouse sobre un componente.

Otros eventos son específicos para cierto tipo de componentes, por tanto los
controladores que se pueden registrar dependerá del tipo de componente, la
siguiente tabla muestra estas relaciones.

Listener
Componente document,
list
action caret change undoable item window other
selection
edit
button
check box
color chooser
combo box
dialog
editor pane hyperlink
file chooser
formatted text
field
frame
internal frame internal frame
list list data
menu menu
menu key
menu item menu drag mouse
option pane
password field
popup menu popup menu
progress bar
radio button
slider
spinner
tabbed pane
table model
table column
table
model
cell editor
text area
text field
text pane hyperlink
toggle button
tree expansion
tree will expand
tree
tree model
tree selection
Tabla 2. Relaciones entre componentes y sus oyentes78

8
Oracle Corporation. The Java SE Tutorial, Listener Supported by Swing Componentes [En línea].
< http://download.oracle.com/javase/tutorial/uiswing/events/eventsandcomponents.html>.
[Consultado 25/05/2010]
Las interfaces Listener pueden tener declarados muchos métodos. Algunas veces
no basta con saber que ocurrió un evento, sino a partir de que acción ocurrió, por
ejemplo si ocurre un evento del mouse (MouseEvent) para la clase que controle el
evento es importante saber cómo se originó este evento, ¿por medio de un clic
izquierdo?, ¿o acaso por un clic derecho?, ¿o solo porque el cursor del mouse
pasó sobre el componente? Por esto las interfaces para eventos como estos,
definen métodos para controlar cada una de estas posibilidades, y que el
desarrollador sea capaz de controlar una interacción de forma detallada. Como
son interfaces, una clase que las implemente se vería obligada a implementar
todos los métodos de interfaz, o tendría que declararse abstracta lo que no sería
posible para nuestro caso, pues necesitamos objetos de estas clases; dada esta
problemática Java provee en su API un conjunto especial de clases llamadas
adaptadoras, que implementan las interfaces Listener, pero dejan todas las
implementaciones de los métodos vacías. Cada interfaz excepto ActionListener,
tiene su adaptador correspondiente. MouseListener tiene a MouseAdapter,
WindowListener tiene a WindowAdapter. Cuando una clase extiende de una clase
adaptadora, solo necesita sobre escribir el método que necesita, y de esta forma
no contaminar el código fuente con métodos vacios que no hacen nada. Por
ejemplo si lo único que se quiere controlar de un evento de ventana es cuando
esta se va a cerrar, entonces lo más conveniente es escribir una clase
controladora que extienda de WindowAdapter, y que sobre escriba únicamente el
método windowClosing. Si la clase se declara implementando WindowListener, se
tendrá que implementar todos los métodos, así sea dejándolos vacios.

LOOK AND FEEL


Como los componentes Swing están desarrollados en Java, no tiene nada que ver
con los que el sistema operativo usa. Por esto es común encontrar que las
aplicaciones Java se ven diferentes que todas las demás que se ejecutan en la
plataforma. Los botones son diferentes, las listas, los arboles, etc. Dado que estas
aplicaciones son multiplataforma, este diseño visual será el mismo en diferentes
sistemas operativos, y esto puede ser una característica no deseable para algunos
desarrolladores.

Pensando en esto se desarrollaron unos componentes conocidos como look and


feel, los cuales permiten modificar el diseño visual de una aplicación, sin cambiar
la implementación. Es decir, no hay que usar clases diferentes, o entrar a
modificar el color de cada componente, ya que los look and feel han sido
desarrollados para que el desarrollador solo se preocupe por conectarlos al inicio
de la aplicación y todo lo que desarrolle lucirá de acuerdo a la configuración del
look and feel.

Los look and feel (de ahora en adelante L&F), son componentes que pueden ser
desarrollados o modificados, lo que ha llevado a que estén disponibles desde
diferentes proyectos L&F que se han liberado para la comunidad y por tanto se
pueden usar sin restricciones. Además Java tiene incluido en su API varios L&F
que permiten modificar la apariencia de las aplicaciones adaptándose a los más
comunes sistemas operativos. El entorno de ejecución provee los siguientes L&F:

1. CrossPlatformLookAndFeel. Este es el L&F de Java, toda aplicación viene por


defecto configurada para que use este L&F. Comúnmente se conoce como Metal y
luce igual en todas las plataformas.
2. SystemLookAndFeel. Con este, las aplicaciones usan el L&F de la plataforma
sobre la que se están ejecutando. El L&F del sistema se determina en tiempo de
ejecución, la aplicación le pregunta al sistema operativo y este le devuelve el
nombre del L&F adecuado.
3. Synth. Es la base para crear L&F propios, basándose en un archivo XML.

El L&F viene con el entorno de ejecución, el cual depende de la plataforma, por


esto no se puede obligar a una aplicación que luzca con el diseño de Windows si
está corriendo en un sistema Linux o viceversa.

Para establecer el L&F en una aplicación, basta con incluir una línea en el código
fuente (Mas las que conlleva el adecuado manejo de excepciones), la cual se
recomienda que sea la primera de la aplicación. Esta línea puede usarse para
configurar el L&F de java, del sistema, o especificar la ruta de paquete completa
en donde encontrará el L&F que se desea usar.

Para usar el L&F de java común a todas las plataformas:


UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());

Para que la aplicación pregunte por el L&F del sistema sobre el que se va a
ejecutar la aplicación:
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

Para usar la ruta completa de la clase del L&F deseado:


UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
La ruta dependerá si el L&F es propio al API o al entorno de ejecución por
ejemplo:
com.sun.java.swing.plaf.gtk.GTKLookAndFeel
com.sun.java.swing.plaf.motif.MotifLookAndFeel
com.sun.java.swing.plaf.windows.WindowsLookAndFeel

Son relativos al entorno de ejecución (paquete java y no javax). Si se está en una


plataforma Windows, se podrá usar la instrucción:
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");

Y de esta forma cargar el L&F de Windows, pero si se ejecuta la misma instrucción


en una plataforma Linux, el compilador la rechazará ya que el entorno de
ejecución no tiene esa clase. El L&F Motif puede usarse en cualquier plataforma,
al igual que los de Java: basic, metal, multi, synth y a partir de la versión de Java
SE 6 actualización 10 (6u10), nimbus.

La ruta en donde se puede encontrar el L&F nimbus es la siguiente:


com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel

ESQUEMA DE TRABAJO CON SWING


En su expresión más sencilla el proceso de construcción de una interfaz gráfica de
usuario en Java podría resumirse en los siguientes pasos:

Crear una clase que extienda del tipo de contenedor de primer nivel que
contendrá la ventana de la aplicación. Por lo general se extiende de JFrame,
indicando que se va a construir un tipo especial de ventana empezando por la
implementación que provee Swing en JFrame.
Declarar como atributos todos los componentes que harán parte de la
ventana, como botones, listas, etiquetas, etc.
Instanciar y configurar correctamente cada componente.
Adicionar según la distribución definida, los componentes al contentPane del
JFrame o a contenedores auxiliares como JPanel. Para distribuir correctamente
los elementos se puede hacer uso de un LayoutManager que permitirá organizar
automáticamente los componentes según el patrón que defina.
Escribir las clases de los objetos que controlarán los eventos, implementando
la interfaz adecuada para el evento que se desea controlar. Estas clases se
pueden escribir como clases internas, independientes, anónimas o incluso la
misma clase de la ventana puede ser controladora a su vez si implementa las
interfaces Listener.
Registrar los controladores en los componentes que pueden llegar a producir
eventos. Este es un punto frecuente de fallos, pues aún si se cumplen todos los
pasos enunciados anteriormente pero no se realiza el registro de los controladores
(que suele ser una única línea de código), la interfaz gráfica no responderá a las
acciones del usuario y será totalmente inútil.

Los invito a continuar con el desarrollo de la unidad con el ejemplo práctico


desarrollado en el video diapositiva publicado en los contenidos de la semana
actual.

You might also like