Sunteți pe pagina 1din 31

11

Interfaces de usuario en Java:


componentes Swing / contenedores
Introducción
A lo largo de los siguientes tres capítulos vamos a tratar el segundo tipo de componentes que ofrece
Java para construir interfaces de usuario, es decir, los componentes Swing incluidos en el paquete
javax.swing.

Muchos de los conceptos vistos en capítulos anteriores, como pueden ser los eventos o los gestores de
diseño siguen siendo válidos para los componentes Swing, así por ejemplo, los gestores de diseño que
utilizan los componentes Swing son los mismos que los vistos en los componentes AWT, de hecho se
debe importar el paquete JAVA.AWT para utilizarlos, pero Swing aporta un nuevo gestor de diseño
(que veremos en el siguiente capítulo, también dedicado por completo al extenso mundo de los
componentes Swing) que se encuentra en el paquete javax.swing.

Lo mismo sucede con los eventos, los componentes Swing utilizan las clases de los eventos incluidas
en el paquete java.awt.event, y además añaden nuevos eventos que se pueden encontrar en el paquete j
avax.swing .event.

Como hemos dicho vamos a tener tres capítulos dedicados a Swing. Swing es bastante extenso y aun
utilizando tres capítulos no lo vamos a ver completamente, sería necesario un curso de la misma
extensión de éste (o más) para tratar Swing de forma completa.

En este primer capítulo vamos a introducir una serie de conceptos de Swing y también se va a tratar un
tipo de componentes Swing, los contenedores Swing.

En el segundo capítulo trataremos el otro gran grupo de componentes Swing, los componentes
atómicos. Y en el último de esta serie de capítulos trataremos otras características de Swing como son
el nuevo gestor de diseño que incorpora (implementado por la clase BoxLayout) y la característica
Pluggable Look & Feel, es decir, aspecto y comportamiento configurables.

JFC y Swing
JFC (Java Foundation Classes) es el nombre que recibe el conjunto de un gran número de
características cuya función primordial es la de permitir la construcción de complejos interfaces de
usuario. El primer anuncio de JFC se realizó en la conferencia de desarrolladores JavaOne y se definió
mediante las características que iba a ofrecer:

160
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

• Componentes Swing: comprenden todos los componentes utilizados para interfaces de usuario
desde botones, barras de menú, diálogos y ventanas hasta cajas de texto, barras de progreso,
paneles con pestañas y listas. A lo largo de este capítulo describiremos algunos de los
componentes Swing, no todos ya que Swing ofrece un gran número de clases agrupadas en 15
paquetes distintos.
• Soporte para Pluggable Look and Feel: es decir, soporte para una apariencia y
comportamiento configurables. Permite a cualquier programa que utilice componentes Swing
definir un tipo de apariencia y comportamiento (Look and Feel). Así por ejemplo una misma
aplicación puede presentar una apariencia y comportamiento al estilo de Java o bien tipo
Windows. En el apartado correspondiente volveremos a retomar esta característica y la
trataremos en detalle.
• API de accesibilidad: permite a tecnologías de rehabilitación tales como lectores de pantalla y
displays Braille obtener información acerca del interfaz de usuario. El API de accesibilidad se
encuentra formando parte de las características avanzadas del lenguaje Java y por lo tanto no
lo vamos a tratar en este curso.
• API Java 2D: al igual que ocurría con la característica o funcionalidad anterior, se trata de un
conjunto de clases especializadas, en este caso, en el tratamiento de gráficos en dos
dimensiones, imágenes y texto. El API Java 2D se escapa también del alcance y pretensiones
de este curso.
• Soporte para arrastrar y soltar (Drag and Drop): permite la posibilidad de arrastrar y soltar
componentes entra aplicaciones Java y aplicaciones en otros lenguajes.

En muchos casos se utilizan indistintamente los términos JFC y Swing sin hacer ningún tipo de
distinción, Swing fue el nombre en clave que recibió el proyecto de Sun encargado de desarrollar los
nuevos componentes para la construcción de interfaces de usuario. La denominación swing aparece
también en los paquetes correspondientes.

Los componentes Swing se encuentran disponibles de dos formas distintas, como parte de la
plataforma Java 2, tanto en la herramienta JDK 1.2 o como en el JDK 1.3, y como una extensión del
JDK 1.1 (versión de Java 1.1) denominada JFC 1.1. En nuestro caso vamos a utilizar la versión que se
encuentran integrada con la plataforma Java 2.

Componentes Swing frente a componentes AWT


En este apartado vamos a comentar las diferencias entre los dos grupos de componentes que ofrece
Java para la creación de interfaces de usuario, y el porqué de la existencia de dos grupos distintos de
componentes.

Los componentes AWT aparecieron en la versión 1.0 del JDK y eran los únicos componentes que se
encontraban disponibles para desarrollar interfaces de usuario. Los componentes AWT se utilizan
principalmente en las versiones 1.0 y 1.1 del lenguaje (que coincidían con las versiones de la
herramienta JDK), aunque la plataforma Java 2 soporta perfectamente los componentes AWT como
hemos podido comprobar en capítulos anteriores.

Desde Sun nos recomiendan que utilicemos si es posible los componentes Swing en lugar de los
componentes AWT.

Los componentes Swing los podemos identificar porque los nombres de sus clases suelen ir
precedidos por la letra J. Así por ejemplo, la clase Button del AWT, tiene su clase correspondiente en
Swing denominada JButton. Los componentes AWT se encuentran en el paquete JAVA.AWT y los
Swing en el paquete javax.swing.

La mayor diferencia entre los componentes AWT y los componentes Swing, es que los componentes
Swing se encuentran implementados sin utilizar ningún tipo de código nativo. Los componentes

161
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

Swing se denominan componentes ligeros (lightweight) y los componentes AWT componentes


pesados (heavyweight).

Otra diferencia importante es la gran potencia y funcionalidad que ofrecen los componentes Swing.
incluso los componentes Swing más sencillos ofrecen una serie de posibilidades que los componentes
AWT no recogen, algunas de estas ventajas de los componentes Swing frente a los AWT son las que
se enumeran a continuación:

• Los botones Swing pueden mostrar imágenes y/o texto.

• Es posible situar bordes en torno a los componentes Swing.

• Los componentes Swing no tienen porque ser rectangulares, por ejemplo, los botones pueden
ser redondos.

• Las tecnologías de rehabilitación pueden obtener información de los componentes Swing de


forma sencilla.

Swing nos permite especificar el aspecto y comportamiento (look and feel) del interfaz de usuario de
nuestra aplicación (más adelante veremos como), sin embargo los componentes AWT tienen el
aspecto y comportamiento de la plataforma nativa sobre la que se ejecutan.

Vamos a comentar brevemente algunas de las razones por las que nos puede interesar utilizar
componentes Swing en lugar de componentes AWT.

• El rico conjunto de componentes que ofrece Swing: botones con imágenes, barras de
herramientas, imágenes, elementos de menú, selectores de color, etc.

• La arquitectura Pluggable Look & Feel, es decir, aspecto y comportamiento configurable y


seleccionable para los elementos del interfaz de usuario.

• Posiblemente en un futuro se ampliarán los componentes Swing disponibles.

Parece hasta ahora que con los componentes Swing todo son ventajas, e incluso que ni siquiera
debemos plantearnos que tipo de componentes debemos utilizar para construir interfaces de usuario,
siempre elegiremos componentes Swing. Pero este razonamiento no es correcto, ya que en la práctica
no resulta tan sencillo.

Se debe señalar que, desgraciadamente, todavía no existen navegadores Web que soporten Swing, más
claro todavía, los navegadores Web actuales, incluso en sus últimas versiones, no implementan la
máquina virtual correspondiente a la plataforma Java 2. Por lo tanto si queremos construir applets que
puedan ejecutarse en cualquier navegador deberemos construir su interfaz gráfica mediante
componentes AWT, aunque en uno de los temas dedicados a los applets veremos un pequeño parche
que utilizaremos para que los navegadores soporten componentes Swing.

Contenedores de alto nivel


Bajo esta nomenclatura se agrupan una serie de clases que se corresponden con componentes Swing
que realizan la función de contenedores de otros componentes y que constituyen la raíz en la jerarquía
de contenedores. Los componentes de alto nivel se basan en los siguientes principios:

• Swing ofrece tres clases que representan a componentes de alto nivel: JFrame (ventana),
JDialog (diálogo) y JApplet. También dentro de los componentes Swing encontramos una
cuarta clase denominada JWindow que representa una ventana sin controles ni título y que se
encuentra siempre por encima de cualquier ventana, es el equivalente a la clase Window de los

162
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

componentes AWT. A lo largo de este capítulo iremos viendo como en los componentes
Swing encontramos equivalentes de los componentes AWT.

• Para aparecer en pantalla todo componente de interfaz de usuario debe formar parte de una
jerarquía de contenedores. Cada jerarquía de contenedores posee un contenedor de alto nivel
como raíz.

• Cada contenedor de alto nivel posee un panel de contenido (content pane) que contiene los
componentes visibles del contenedor de alto nivel del interfaz de usuario correspondiente.

• Opcionalmente se puede añadir una barra de menú a un contenedor de alto nivel. La barra de
menú se sitúa en el contenedor de alto nivel, pero fuera del panel de contenido.

Veamos un sencillo ejemplo que muestra un contenedor de alto nivel. Se trata de un objeto de la clase
JFrame que contiene una barra de menú (JMenuBar) de color azul y una etiqueta (JLabel) de color
amarillo. En la Figura 62 se puede ver el aspecto del contenedor.

Figura 62

Y el código fuente completo de este ejemplo es el que aparece en el Código fuente 118.

import java.awt.*;
import javax.swing.*;
public class ContenedorAltoNivel {
public static void main(String s[ ] ) {
//se crea la ventana raíz de la jerarquía de contenedores
JFrame ventana = new JFrame("Contenedor de alto nivel");
//se crea la etiqueta
JLabel etiquetaAmarilla = new JLabel("");
etiquetaAmarilla.setOpaque(true);
etiquetaAmarilla.setBackground(Color.yellow);
etiquetaAmarilla.setPreferredSize(new Dimensión(200, 180));
//se crea la barra de menú
JMenuBar barraMenuCyan = new JMenuBar() ;
barraMenuCyan.setOpaque(true) ;
barraMenuCyan.setBackground(Color.cyan);
barraMenuCyan.setPreferredSize(new Dimensión(200, 20));
//se añaden la etiqueta y la barra de menú a la ventana
ventana.setJMenuBar(barraMenuCyan);
ventana.getContentPane().add(etiquetaAmarilla, BorderLayout.CENTER);
//se muestra la ventana
ventana.pack() ;
ventana.setVisible(true);
}
}
Código fuente 118

163
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

A la vista de este código podemos realizar los siguientes comentarios. Se han importado los
paquetes JAVA.AWT y javax.swing. El paquete JAVA.AWT es necesario para utilizar las clases
Dimensión, Color y BorderLayout, como se puede observar aunque utilicemos componentes
Swing vamos a necesitar de los componentes AWT.

También podemos comprobar la forma en la que se añade un componente a un panel de


contenido de un contenedor de alto nivel como puede ser un objeto de la clase JFrame, y también
como añadir una barra de menú, en este mismo apartado veremos en más detalle el código que
realiza estas funciones.

La jerarquía de contenedores del ejemplo queda como muestra el esquema de la Figura 63

Figura 63

Veamos un ejemplo más para ilustrar las jerarquías de contenedores. Para ello nos debemos fijar en la
Figura 64.

Figura 64

En este ejemplo se han utilizado los siguientes componentes Swing:


• Una ventana principal (JFrame).
• Un panel (JPanel).
• Un botón (JButton).
• Una etiqueta (JLabel).

Al panel se le ha añadido un borde mediante la clase BorderFactory para mostrar el agrupamiento de


forma más clara entre el botón y la etiqueta. El código fuente de este ejemplo es el que aparece en el
Código fuente 119.

import javax.swing.*;
import java.awt.*;
public class Ventana{
public static void main(String[] args) {
//se establece el Look & Feel
try {
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
} catch (Exception e) { }
//se crean los componentes
JFrame ventana = new JFrame("Ventana");
JLabel etiqueta = new JLabel(" Soy una etiqueta");
JButton botón = new JButton("Soy un botón");
JPanel panel = new JPanel();

164
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

//se asigna un borde y un gestor de diseño al panel


panel.setBorder(BorderFactory.createLineBorder(Color.red,5));
panel.setLayout(new GridLayout(0, 1));
//se añaden al panel el botón y la etiqueta
panel.add(botón); panel.add(etiqueta) ; //se añade el panel al panel de contenido de la ventana
ventana.getContentPane().add(panel, BorderLayout.CENTER);
//se muestra la ventana
ventana.pack();
ventana.setVisible(true);
}
}
Código fuente 119

Este código adelanta algo que veremos en detalle en el apartado correspondiente, cómo asignar un
aspecto y comportamiento (Look & Feel) determinado a nuestro interfaz de usuario, esto aparece en
las primeras líneas del método main() y en este caso se establece el aspecto y comportamiento de Java.

Vamos a pasar a describir las funciones que presentan cada uno de los componentes Swing utilizados
en el ejemplo.

En este ejemplo la ventana representada mediante la clase JFrame es el contenedor de alto nivel,
igualmente podría tratarse de otro componente de alto nivel como podría ser un objeto de la clase
JApplet o JDialog.

El panel es un contenedor intermedio, su propósito es el de simplificar la situación del botón y la


etiqueta, para que sea visible se le ha asignado un borde de color rojo. Otros contenedores intermedios
pueden ser paneles con pestañas (JTabbedPane) y paneles de scroll (JScrollPane), que juegan un papel
más visible e interactivo dentro del interfaz de usuario.

Y por último y el botón y la etiqueta se denominan componentes atómicos, son componentes que no
contienen otros componentes Swing, como ocurría con los anteriores, sino que tienen entidad
suficiente para presentar por sí mismos información al usuario. A menudo los componentes atómicos
tienen como función obtener información del usuario. Swing ofrece un gran número de componentes
atómicos (en este capítulo veremos algunos de ellos) como pueden ser listas desplegables
(JComboBox), cajas de texto (JTextField) o tablas (JTable).

En la Figura 65 se muestra el diagrama con la jerarquía de contenedores que presenta este ejemplo.

Figura 65

165
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

Como se puede observar en la Figura 65, incluso el programa Swing más sencillo presenta múltiples
niveles en su jerarquía de contenedores, además, como ya hemos dicho la raíz de esta jerarquía
siempre es un contenedor de alto nivel.

Cada contenedor de alto nivel indirectamente contiene un contenedor intermedio llamado panel de
contenido (content pane), y normalmente el panel de contenido contiene, directa o indirectamente,
todos los componentes visibles de la ventana del interfaz de usuario. La excepción a esta regla son las
barras de menú, que se sitúan en un lugar especial fuera del panel de contenido, como vimos en el
primer ejemplo de este apartado.

Para añadir un componente a un contenedor se utiliza una de las distintas formas del método add(),
como ya vimos en el tema dedicado a los componentes AWT.

Como regla general, una aplicación Java con un interfaz de usuario basado en componentes Swing,
tiene al menos una jerarquía de contenedores con un objeto de la clase JFrame como raíz de la misma.
Por ejemplo, si una aplicación tiene una ventana principal y dos diálogos, la aplicación presentará tres
jerarquías de contenedores, y por lo tanto tres contenedores de alto nivel. Una de las jerarquías de
contenedores tiene a un objeto de la clase JFrame como raíz, y cada una de las otras dos jerarquías un
objeto de la clase JDialog como raíz.

Un applet basado en Swing tiene al menos una jerarquía de contenedores y su raíz es un objeto de la
clase JApplet. Por ejemplo un applet que muestra un diálogo tiene dos jerarquías de contenedores, los
componentes en la ventana del navegador tienen como raíz un objeto JApplet, y los que se encuentran
en el diálogo tienen como raíz de su jerarquía de componentes un objeto de la clase JDialog.

Hasta ahora hemos visto un par de ejemplos que por un lado nos han mostrado como funcionan las
jerarquías de contenedores, y por otro, nos ha mostrado como utilizar algunos de los componentes
Swing, aunque más adelante veremos algunos de ellos con más detalle.

Para obtener una referencia al panel de contenido de un componente de alto nivel debemos utilizar el
método getContentPane(), que devuelve un objeto de la clase Container. Por defecto el panel de
contenido es un contenedor intermedio que hereda de la clase JComponent y que tiene como gestor de
diseño un BorderLayout.

Una vez que tenemos una referencia al panel de contenido podremos añadir los componentes que
consideremos necesarios utilizando una sentencia similar a la que muestra el Código fuente 120.

ventana.getContentPane().add(componente,BorderLayout.CENTER);
Código fuente 120

Todos los contenedores de alto nivel pueden tener, en teoría, una barra de menú, sin embargo en la
práctica las barras de menú se utilizan únicamente en ventanas y en raras ocasiones en applets. Para
añadir una barra de menú a un contenedor de alto nivel, crearemos un objeto de la clase JMenuBar,
añadiremos los elementos de menú que se consideren necesarios y por último se lanzará sobre el
contenedor de alto nivel el método setMenuBar(), pasándole por parámetro el objeto JMenuBar
correspondiente.

ventana.setMenuBar(obJMenuBar) ;
Código fuente 121

Todo contenedor de alto nivel además de poseer un panel de contenido, poseen otro panel llamado
panel raíz (root pane). Normalmente este panel intermedio no se suele utilizar, su función es la de
gestionar el panel de contenido y la barra de menú junto con otros dos contenedores.

Estos dos contenedores son el panel de capas (layered pane) y el panel de cristal (glass pane). El panel
de capas contiene directamente la barra de menú y el panel de contenido, y además permite ordenar
los componentes que se vayan añadir con detenimiento (Z-order), es decir, permite organizar los

166
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

componentes del interfaz de usuario en capas. Esto puede ser útil para mostrar menús de aparición
súbita (popup menus) por encima de otros componentes.

El panel de cristal suele permanecer oculto y se encuentra por encima de todos los elementos del panel
raíz. Este panel es útil para interceptar eventos o pintar sobre un área que ya contiene otros
componentes, se utiliza sobre todo para interceptar eventos de entrada que suceden sobre el
contenedor de alto nivel. En la Figura 66 se puede ver un esquema que muestra la disposición de los
distintos paneles que podemos encontrar en un componente de alto nivel.

Figura 66

A continuación vamos a comentar los distintos componentes de alto nivel: JFrame, JDialog y JApplet.

JFrame
Ya hemos visto este componente Swing realizando las labores de contenedor de alto nivel, un objeto
de la clase JFrame representa a una ventana con bordes, título y botones que permiten cerrar y
maximizar la ventana.

Las aplicaciones Java que poseen interfaz de usuario al menos utilizan un JFrame, y también lo hacen
aveces los applets.

Veamos la utilización de la clase JFrame mediante un sencillo ejemplo. Se trata de una ventana que
contiene una etiqueta y que al pulsar el cierre de la misma se finalizará la ejecución de la aplicación.
Su código es el Código fuente 122.

import java.awt.*;
import j ava.awt.event.*; import javax.swing.*; public class Ventanaf
public static void main(String s[ ] ) {
JFrame ventana = new JFrame("Ventana Sencilla");
ventana.addWindowListener(new WindowAdapter();
public void windowClosing(WindowEvent e) {
System.exit(0);
JLabel etiqueta = new JLabel("Soy una etiqueta");
etiqueta.setPreferredSize(new Dimensión(175, 100);
ventana.getContentPane().add(etiqueta, BorderLayout.CENTER)
ventana.pack () ;
ventana.setVisible(true);
}
}
}
Código fuente 122

167
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

Y el aspecto de la ventana es el que vemos en la Figura 67.

Figura 67

En la primera línea del método main() se utiliza el constructor de la clase JFrame que nos permite
indicar el título de la ventana mediante una cadena que pasamos como parámetro, otra versión de este
constructor es sin argumentos.

A continuación se añade un oyente para los eventos de la ventana, en este caso se implementa
únicamente el método windowClosing() para finalizar la ejecución de la aplicación. En las siguientes
líneas se crea y añade una etiqueta (JLabel) al panel de contenido de la ventana.

Por último se lanzan los métodos pack() y setVisible() sobre la instancia de la clase JFrame. El método
pack() de un tamaño a la ventana de forma que todos sus contenidos tengan el tamaño especificado o
superior, una alternativa al método pack() es le método setSize() en el que se puede especificar de
forma explícita las dimensiones de la ventana. Al método setVisible() se le pasa el parámetro true para
que muestre la ventana en la pantalla.

Por defecto cuando se pulsa el botón de cierre de la ventana, la ventana se oculta, sin la necesidad de
utilizar ningún tratamiento de eventos, para cambiar este comportamiento se puede utilizar el método
setDefaultCloseOperation() o bien implementar un tratamiento de eventos similar al del ejemplo.

El parámetro que se le pasa al método setDefaultCloseOperation() debe ser una de las siguientes
constantes:

• DONOTHINGONCLOSE: en este caso cuando se pulsa el botón de cierre de la ventana no


ocurre nada, la ventana sigue visible.

• HIDEONCLOSE: es el valor por defecto, cuando se pulsa el botón de cierre la ventana se


oculta, pero sigue existiendo, teniendo la posibilidad de mostrarse la ventana de nuevo si así lo
indicamos en el programa.

• DISPOSEONCLOSE: al cerrar la ventana se elimina de la memoria y de la pantalla, es decir,


en este caso se liberan todos los recursos que estaban siendo utilizados por la ventana.

La clase JFrame hereda de la clase java.awt.Frame y por lo tanto hereda todos los métodos de la clase
Frame, como pueden ser setSize(), pack(), setTitle(), setVisible() y getTitle(). Además de los métodos
de la clase java.awt.Frame, la clase JFrame tiene los siguientes métodos propios:

• void setDefaultCloseOperation(int): asigna el tipo de operación que va a realizar la ventana


cuando el usuario pulse el botón de cierre de la ventana. Ya hemos visto las posibles acciones.

• int getDefaultCloseOperation(): devuelve la operación de cierre por defecto asignada a la


ventana.

• void setContentPane(Container): asigna a la ventana un panel de contenido, que va a ser el que


contenga todos los componentes visibles del interfaz de usuario de la ventana. Este método
permite utilizar nuestro propio panel de contenido, lo normal es utilizar un objeto de la clase

168
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

JPanel para crear el panel de contenido, en el Código fuente 123 se puede observar como se
crea un objeto JPanel que luego va a ser el panel de contenido de una ventana.

JPanel panelContenido=new JPanel();•


panelContenído.setLayout(new BorderLayout());
panelContenído.add(componente,BorderLayout.CENTER);
panelContenído.add(otroComponente,BorderLayout.SOUTH);
ventana.setContentPane(panelContenído);
Código fuente 123

• Container getContentPane(): devuelve el panel de contenido de la ventana, este método se


suele utilizar para una vez que tenemos una referencia al panel de contenido de la ventana
añadir componentes a la misma.
• void setMenuBar(MenuBar): asigna a la ventana una barra de menú determinada representada
por un objeto de la clase MenuBar.
• JMenuBar getMenuBar(): devuelve la barra de menú que tiene asignada la ventana.
• void setGlassPane(Component): permite asignar un panel de cristal a la ventana.
• Component getGlassPane(): devuelve el panel de cristal de la ventana.

JDialog, JOptionPane
Vamos a pasar ahora a comentar el segundo tipo de contenedores de alto nivel, los diálogos, que son
un tipo de ventana más limitada que las ventanas representadas por la clase JFrame. Hay varias clases
que ofrecen diálogos:
• JOptionPane: permiten crear sencillos diálogos estándar.
• ProgressMonitor: muestra un diálogo que muestra el progreso de una operación.
• JColorChooser: ofrece un diálogo estándar para la selección de colores.
• JFileChooser: ofrece un diálogo estándar para la selección de un fichero.
• JDialog: permite crear directamente diálogos completamente personalizados.

Como se indica al principio de esta sección nosotros únicamente nos vamos a encargar de las clase
JOptionPane y JDialog.

Todo diálogo es dependiente de una ventana determinada, si la ventana se destruye también sus lo
harán sus diálogos asociados. Cuando la ventana se transforma en icono sus diálogos desaparecen de
la pantalla, cuando se maximiza la ventana los diálogos vuelven a aparecer.

Los diálogos pueden ser modales, cuando un diálogo modal se encuentra visible se bloquea la entrada
del usuario en todas las demás ventanas del programa. Los diálogos que ofrece la clase JOptionPane
son modales, para crear un diálogo no modal se debe hacer uso de la clase JDialog que permitirá
indicar si el diálogo que se crea va a ser modal o no.

La clase JDialog hereda de a clase AWT java.awt.Dialog, añade a la clase Dialog un panel raíz (root
pane) y soporte para la operación por defecto de cierre. Como se puede observar son las mismas
características que ofrecía la clase JFrame sobre la clase Frame del AWT.

Cuando se utiliza la clase JOptionPane en realidad también estamos haciendo uso de la clase JDialog
de forma indirecta, ya que la clase JOptionPane es un contenedor que puede crear de forma automática
una instancia de la clase JDialog y añadirse al panel de contenido de ese diálogo. A continuación
vamos a comentar las distintas características de la clase JOptionPane.

169
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

Mediante la clase JOptionPane podemos crear distintos tipos de diálogos, JOptionPane ofrece soporte
para mostrar diálogos estándar, indicar los iconos, especificar el título y texto del diálogo y los textos
de los botones que aparecen.

En cuanto a los iconos que se muestran en el diálogo facilitado por JOptionPane, podemos utilizar
iconos personalizados, no utilizar ningún tipo de icono, o utilizar uno de los cuatro iconos estándar
que ofrece la clase JOptionPane, estos iconos son los de pregunta, información, advertencia y error. El
aspecto de estos iconos variará según el Look & Feel (aspecto y comportamiento) que se aplique.

Para mostrar diálogos modales sencillos se utilizará directamente uno de los métodos
showXXXDialog() de la clase JOptionPane. Este conjunto de métodos son métodos estáticos y por lo
tanto se lanzarán sobre una instancia concreta de la clase, sino que se lanzaran de forma directa sobre
laclase.

Si lo que necesitamos es controlar el comportamiento del diálogo cuando se cierre o si el diálogo no


debe ser modal entonces instanciaremos un objeto de la clase JOptionPane y lo añadiremos a un
objeto de la clase JDialog. Veamos a continuación los principales métodos showXXXDialog() de la
clase JOptionPane.

El primero de estos métodos es el método showMessageDialog(), que muestra un diálogo modal con
un botón de aceptar. Se puede especificar el mensaje, el icono y el título que muestra el diálogo. Este
método se encuentra sobrecargado y ofrece tres versiones distintas:

• void showMessageDialog(Component componentePadre, Object mensaje): el primer


parámetro indica el componente padre del que depende, puede ser una ventana, un
componente dentro de una ventana o nulo y el segundo el mensaje que se muestra, suele ser
una cadena de texto que podemos dividir en varias líneas utilizando el carácter de nueva línea
(\n).

• void showMessageDialog(Component componentePadre, Object mensaje, String título, int


tipoMensaje): en este caso se especifica también el título, que será una cadena, y el tipo de
mensaje a mostrar. Este último parámetro determinará el icono que se va a mostrar en el
diálogo, para ello se utilizan una serie de constantes definidas en la clase JOptionPane, estas
constantes son: PLAIN MESSAGE (sin icono), ERROR MESSAGE (icono de error),
INFORMATION_MESSAGE (icono de información), WARNING MESSAGE (icono de
advertencia) y QUESTION_MESSAGE (icono de pregunta).

• void showMessageDialog(Component componentePadre, Object mensaje, String título, int


tipoMensaje, Icón icono): en esta última versión del método podemos indicar un icono
personalizado para que se muestre en el diálogo.

Veamos algunos ejemplos con el método showMessageDialog(). Podemos añadir las distintas
sentencias de creación de diálogos que vamos a ver ahora al ejemplo de la sección anterior en la que
tratábamos la clase JFrame, la instancia de la clase JFrame, llamada ventana va a ser el componente
padre de los diálogos.

Si añadimos la línea que muestra el Código fuente 124, a nuestra clase Ventana de la sección anterior,
obtendremos el resultado que aparece en la Figura 68.

JOptionPane.showMessageDialog(ventana,"Esto es un mensaje", "Titulo",JOptionPane.WARNING_MESSAGE);


Código fuente 124

170
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

Figura 68

Otras variaciones sobre la sentencia anterior se muestran a continuación con sus correspondientes
resultados.

JOptionPane.showMessageDialog(ventana,"Esto es un mensaje");
Código fuente 125

En este caso se muestra el título y tipo de mensaje por defecto.

Figura 69

Imagelcon icono = new Imagelcon("icono.gif");

JOptionPane.showMessageDialog(ventana,"Esto es un mensaje","Título", JOptionPane.INFORMATION_MESSAGE,icono);


Código fuente 126

En este otro caso indicamos un icono personalizado para que se muestre en el diálogo.

Figura 70

JOptionPane.showMessageDialog(ventana,"Esto es un mensaje","Titulo", JOptionPane.ERROR_MESSAGE);

Código fuente 127

Figura 71

171
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

Como se puede comprobar en todos los ejemplos, si pulsamos el botón etiquetado como OK, el
diálogo se cerrará.

Otro método de la clase JOptionPane que muestra un diálogo es el método showConfirmaDialogO. En


este caso este método muestra un diálogo de confirmación, para que el usuario seleccione entre los
botones correspondientes. Este método, al igual que el anterior, se encuentra sobrecargado y por lo
tanto ofrece tres versiones distintas, que pasamos a comentar a continuación.
• int showConfirmDialog(Component componentePadre, Object mensaje): este método muestra
un diálogo modal con los botones, que representan las opciones disponibles, si, no y cancelar,
y además con el título por defecto.
• int showConfirmDialog(Component componentePadre, Object mensaje, String título, int
tipoOpción): en este caso podemos especificar el título del diálogo de confirmación y el tipo
de opciones que se van a mostrar, para esto último utilizaremos las siguientes constantes
ofrecidas por la clase JOptionPane: DEFAULT OPTION, YES NO OPTION, YES NO
CANCEL OPTION y OK CANCEL OPTION.
• int showConfirmDialog(Component componentePadre, Object mensaje, String título, int
tipoOpción, int tipoMensaje): en esta versión del método podemos indicar además el tipo de
mensaje que se muestra en el diálogo, de la misma forma que lo hacíamos en el método
showMessageDialog().
• int showConfirmDialog(Component componentePadre, Object mensaje, String título, int
tipoOpción, int tipoMensaje, Icón icono): en esta última versión especificamos un icono
personalizado que se va a mostrar en el diálogo de conformación correspondiente.

Como se puede observar en todas las versiones del método showConfirmDialog() se devuelve un
entero (int), este entero va a recoger la selección que ha realizado el usuario, es decir, indicará el
botón que ha sido pulsado. El entero que devuelve este método se corresponde con uno de los valores
de las siguientes constantes de la clase JOptionPane: YES OPTION, NO OPTION, CANCEL_
OPTION, OKOPTION y CLOSEDOPTION (el usuario cierra el diálogo sin pulsar ninguna de las
opciones disponibles).

Al igual que ocurría con el método anterior, vamos a ver ejemplos de utilización del método
show-ConfirmDialog.

JOptionPane.showConfirmDialog(ventana,"¿Desea formatear el disco?");


Código fuente 128

En este caso se muestra el diálogo de confirmación por defecto.

Figura 72

JOptionPane.showConfirmDialog(ventana,"¿Desea formatear el disco?","Confirme operación",


JOptionPane.YES_NO_OPTION,JOptionPane.WARNING_MESSAGE)

Código fuente 129

172
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

Figura 73

El siguiente método que vamos a tratar de la clase JOptionPane va a ser el método


showOptionDialogO.

Este método es mucho más potente que los vistos anteriormente, ya que permite una mayor
personalización del diálogo. La función de este método es la de mostrar un diálogo modal con los
botones, iconos, mensaje y títulos especificados para que el usuario seleccione entre las distintas
opciones que se le ofrecen, con este método podremos indicar los botones que queremos aparezcan en
el diálogo.

El método showOptionDialogO se diferencia del método showConfirmDialog() principalmente en


que permite especificar las etiquetas de los botones que aparecen y además permite especificar la
opción seleccionada por defecto.

La sintaxis de este método es la siguiente:

int showOptionDialog(Component componentePadre, Object mensaje, String título, int tipoOpción,


int tipoMensaje, Icón icono, Object[] opciones, Object valorlnicial)

Vamos a comentar los distintos parámetros de este nuevo método. Los tres primeros parámetros son
los mismos que los vistos en el método showMessageDialog() y además tienen el mismo significado.
En el tipo de opción se especifica el conjunto de opciones que se van a presentar al usuario, y por lo
tanto se corresponderán con las constantes vistas en el método showConfirmDialog().

Los dos siguientes parámetros, tipo de mensaje y el icono personalizado, tiene el mismo cometido
que el método showMessageDialog(). El siguiente parámetro es un array de objetos que se va a
corresponder con un array de cadenas que se van a mostrar en cada uno de los botones del diálogo, es
decir, podemos utilizar nuestras propias etiquetas pera mostrar en los botones. El último parámetro
indica cual es la opción que se encuentra seleccionada por defecto.

Como se puede observar en la sintaxis del método showOptionDialogO se devuelve un entero (int),
este entero tiene la misma función que el que devolvía el método showConfirDialog(), es decir, va a
recoger la selección que ha realizado el usuario, es decir, indicará el botón que ha sido pulsado. Se
debe indicar que aunque utilicemos etiquetas personalizadas para nuestros botones, se siguen
devolviendo los mismos valores de las constantes, así por ejemplo un diálogo del tipo YES NO
OPTION siempre devolverá los valores: YES OPTION, NO OPTION o CLOSED OPTION.

Ahora se va a mostrar ejemplos de uso del método showOptionDialogO. Estos ejemplos son
únicamente unas cuentas sentencias que podemos incluir, como ocurría con los métodos anteriores,
en nuestra ya conocida clase Ventana.

Object[ ] opciones={"Vale", "Ni hablar"}


Imagelcon icono = new Imagelcon("icono.gif");
JOptionPane.showOptionDialog(ventana,"¿Desea formatear el disco?","Confirme operación,
JOptionPane.YES_NO_OPTION,JOptionPane.WARNINGMESSAGE, icono, opciones, opciones[1]);
Código fuente 130

173
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

Se muestra un diálogo con las opciones si/no pero con unas etiquetas de botones personalizadas, así
como con un icono personalizado, además es el segundo botón el que se encuentra seleccionado por
defecto.

Figura 74

El último método que vamos a ver de la clase JOptionPane es el método showInputDialog(), este
método va a permitir obtener información de entrada del usuario a través del diálogo, ya sea a través
de una caja de texto o a través de un una lista de opciones. El diálogo que se muestra va a tener dos
botones, uno de aceptar y otro de cancelar, si el usuario pulsa el botón de aceptar indicará que ha
introducido una información que podemos recuperar. Este método se encuentra sobrecargado, y ofrece
las siguientes versiones:

• Object showInputDialog(Component componentePadre, Object mensaje): muestra un diálogo


con el mensaje correspondiente que requiere una entrada del usuario a través de una caja de
texto.

• Object showInputDialog(Component componentePadre, Object mensaje, String título, int


tipoMensaje): en esta caso nos permite especificar un título y un tipo de mensaje (ya
conocemos las constantes correspondientes).

• Object showInputDialog(Component componentePadre, Object mensaje, String título, int


tipoMensaje, Icón icono, Object opciones, Object opciónSeleccionada): en este método se
permite indicar un icono personalizado y un conjunto de opciones en forma de lista
desplegable para que el usuario seleccione una de ellas además se permite seleccionar una
opción por defecto.

• String showInputDialog(Object mensaje): en este caso no se indica nada más que el mensaje
que se va a mostrar al usuario, sin utilizar ningún componente padre, por lo que el diálogo se
situará en el centro de la pantalla, ya que en los otros casos se centra siempre con respecto al
componente padre, aunque de todas forma sigue bloqueando a la ventana que lo ha generado.

Como se puede comprobar siempre se devuelve un objeto de la clase String, que se va a corresponder
con una cadena que va a representar la información indicada por el usuario, ya sea a través de una caja
de texto una de una lista de opciones disponibles. En los siguientes ejemplos se muestra la utilización
del método showInputDialog().

En este caso se va a recoger el dato facilitado por el usuario y mostrarlo en la salida estándar de la
aplicación.

String respuesta=JOptionPane.showInputDialog(ventana,"¿Cuál es tu nombre?");


System.out.println("El nombre del usuario es: "+respuesta);
Código fuente 131

174
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

Figura 75

Object [] valores={"Rojo","Verde","Azul","Negro","Amarillo"};
Imagelcon icono = new Imagelcon("icono.gif");
Object respuesta=JOptionPane.showInputDialog(ventana,"¿Cuál es tu color favorito?", "Selección de
color",JOptionPane.QUESTION_MESSAGE, icono,valores,valores[2]);
System.out.println("El color favorito del usuario es el: "+respuesta);
Código fuente 132

En este caso se muestra una lista con las opciones disponibles, para que el usuario seleccione la que
desee. También se ha utilizado un icono personalizado.

Figura 76

Hasta ahora hemos visto los métodos que nos ofrece la clase JOptionPane para mostrar distintos tipos
de diálogo. Estos diálogos tienen en común una serie de características: al pulsar alguno de los
botones que contienen se cierran, también se cierran cuando el usuario pulsa el cierre del diálogo y por
último son todos modales. En algunos casos estos diálogos nos servirán, ya que su comportamiento se
puede adecuar a nuestras necesidades, pero en otros casos esto puede no ser así.

En algunos casos nos puede interesar validar la información ofrecida por el usuario en un diálogo, o
también nos puede interesar utilizar un diálogo que no sea modal. En estos casos en los que deseamos
personalizar al máximo los diálogos utilizaremos la clase JDialog conjuntamente con la clase
JOptionPane. Para ello necesitamos crear una instancia de la clase JOptionPane para añadirla al objeto
JDialog correspondiente.

La clase JOptionPane presenta múltiples constructores que permiten especificar el mensaje que se va a
mostrar, el tipo de mensaje, el tipo de opciones, el icono personalizado, las opciones disponibles y la
opción seleccionada por defecto.

Una vez creado el objeto JOptionPane, deberemos crear el objeto JDialog que lo va a contener,
algunos de los constructores ofrecidos por la clase JDialog son:

• JDialog(): crea un diálogo no modal, sin título definido y sin ninguna ventana propietaria.

• JDialog(Frame ventanaPropietaria): se indica la ventana a la que se encuentra asociado el


diálogo.

• JDialog(Frame ventanaPropietaria, boolean modal): se indica si el diálogo va a ser modal o


no.

175
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

• JDialog(Frame ventanaPropietaria, boolean modal, String título): se especifica además el


título que va a tener el diálogo.

Si ya tenemos instanciados el objeto JOptionPane y el objeto JDialog, únicamente nos queda asignar
al diálogo (JDialog) su contenido (JOptionPane), para ello utilizamos el método setContentPane() de
la clase JDialog, y que es común, como ya hemos comentado, a todos los contenedores de alto nivel.

A continuación se muestra este proceso con un ejemplo que consiste en una sencilla aplicación Java
que muestra una ventana y un diálogo asociada a la misma.
import j ava.awt.*;
import j ava.awt.event.*;
import javax.swing.*;
public class Dialogo{
public static void main(String s[] ) {
JFrame ventana = new JFrame("Ventana Sencilla");
ventana.setSize(175,100);
ventana.setVisible(true);
JOptionPane contenido=new JOptionPane("Esto es un mensaje",
JOptionPane.INFORMATION_MESSAGE,JOptionPane.YES_NO_CANCEL_OPTION);
JDialog dialogo=new JDialog(ventana,"Esto es un diálogo",true);
dialogo.set Cont ent Pane(cont eni do) ;
dialogo.setLocationRelativeTo(ventana);
dialogo.pack(); dialogo.setVisible(true);
}
}
Código fuente 133

El resultado es un diálogo modal como el de la Figura 77.

Figura 77

Como se puede comprobar la pulsación de los botones del diálogo no tiene el efecto que tenían
anteriormente, si queremos que realicen alguna operación cuando se pulsen, deberemos hacerlo a
través de una gestión de eventos a través del código de nuestra aplicación. Aunque si pulsamos el
cierre del diálogo éste se sigue cerrando, ya que la operación tiene asignada por defecto para el cierre
es HIDEONCLOSE, es decir, ocultarse en el cierre, como ocurría con la clase JFrame.

En el código se puede observar que se utiliza el método setLocationRealtiveTo(), este método centra
el diálogo de forma relativa al componente que le pasamos por parámetro.

Otros métodos de la clase JDialog son los siguientes:

• Container getContentPane(): devuelve el panel de contenido del diálogo.

• int getDefaultCloseOperation(): devuelve la operación de cierre por defecto que tiene


asignada el diálogo.

• void setDefaultCloseOperation(int operación): asigna una operación de cierre por defecto al


diálogo.

176
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

JApplet
Este es el tercero de los contenedores de alto nivel. Esta clase hereda de la clase java.applet.Applet, es
por lo tanto la versión Swing de la clase Applet.

La clase JApplet aporta dos características esenciales a los applets, ofrece soporte para tecnologías de
rehabilitación y ofrece un panel raíz, con todo lo que ello supone, es decir, añadir componentes al
panel de contenido, posibilidad de tener una barra de menú, etc.

Todavía no hemos visto con detenimiento la utilización de applets, únicamente los hemos definido de
manera sencilla, por lo tanto en el presente capítulo no vamos a comentar nada más de la clase
JApplet, será en los capítulos dedicados a los applets dónde se trate la misma.

Contenedores intermedios
Los contenedores intermedios son contenedores Swing, que aunque no son contenedores de alto nivel,
su labor principal es la de contener otros componentes. Estos contenedores se siguen basando en la
jerarquía de contenedores de Swing que ya hemos visto anteriormente.

Swing ofrece una serie de contenedores de propósito general:

• JPanel: es le más flexible y utilizado de todos ellos. Se utiliza normalmente para agrupar
componentes, se le puede asignar gestores de diseño y bordes. Los paneles de contenido de los
contenedores de alto nivel suelen ser de la clase JPanel.

• JScrollPane: ofrece una vista de scroll de un componente, suele contener componentes


grandes o que pueden crecer. Se utilizan debido a las limitaciones del tamaño de la pantalla.

• JSplitPane: este panel agrupa dos componentes, uno al lado del otro. El usuario puede ajustar
la línea divisora que separa ambos componentes arrastrándola. El aspecto es similar al que
ofrece, por ejemplo, el explorador de Windows, la vista del árbol de directorios se encuentra
separada de la vista de contenidos de un directorio.

• JTabbedPane: contiene muchos componentes pero sólo puede mostrar un conjunto de ellos a
la vez, el usuario puede ir cambiando entre los distintos conjuntos de manera sencilla. Un
ejemplo podrían ser las distintas pestañas de una hoja de propiedades.

• JToolBar: grupa una serie de componentes (normalmente botones) en una fila o en una
columna, pueden permitir al usuario arrastrar la barra a distintos lugares. Un ejemplo pueden
ser las barras de herramientas de un procesador de textos como MS Word.

Además también existen los siguientes contenedores intermedios que se encuentran más
especializados:

• JInternalFrame: permite mostrar una ventana dentro de otra. Parece una ventana y ofrece toda
su funcionalidad pero debe parecer siempre dentro de otra ventana (contenedor de alto nivel)
que la contiene.

• JLayeredPane: este panel ofrece una tercera dimensión, la profundidad, para poder posicionar
componentes de esta forma. Esta tercera dimensión se denomina también Z-order. Al añadir
un componente a un panel de este tipo se especifica su profundidad mediante un entero,
cuanto mayor sea el entero especificado mayor será la profundidad en la que se sitúa el
componente.

177
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

• JRootPane: esta clase representa el panel raíz de un contenedor de alto nivel, como ya vimos
en el apartado anterior el panel raíz esta formado por las siguientes partes: panel de capas,
panel de contenido, panel de cristal y barra de menú.

A continuación vamos a comentar algunos de estos paneles intermedios, no vamos a tratar todos ya
nos excederíamos en la extensión del presente curso, no se debe olvidar que Swing tienen un gran
número de componentes.

JPanel
Esta clase permite construir paneles de propósito general para contener componentes Swing. Por
defecto un panel no muestra nada en pantalla a excepción de su fondo, también por defecto los paneles
son opacos, aunque se pueden hacer transparentes mediante el método setOpaque() pasándole el valor
false por parámetro.

La clase JPanel es la versión Swing de la clase Panel de AWT. La clase JPanel permite asignar un
gestor de diseño al panel para indicar la forma en la que se van añadiendo los distintos componentes al
mismo, por defecto el gestor de diseño de un objeto JPanel es un FlowLayout.

Swing utiliza los mismos gestores de diseño que vimos para los componentes AWT, de hecho se debe
importar el paquete JAVA.AWT para poder utilizarlos, pero se añade un nuevo gestor mediante la
clase BoxLayout, que veremos en el apartado correspondiente.

Para añadir componentes lo haremos de la misma forma que veíamos en los paneles AWT, es decir,
con las distintas versiones de los métodos add(). En el Código fuente 134 se muestra la forma de
utilizar esta clase.

import j ava.awt.*;
import j ava.awt.event.*;
import javax.swing.*;
public class Panel{
public static void main(String s[]) {
JFrame ventana = new JFrame("Ventana Sencilla");
JPanel panel=new JPanel () ;
panel.setLayout(new BorderLayout());
JLabel etiquetal = new JLabel("Soy una etiqueta",JLabel.CENTER);
etiquetal.setPreferredSize(new Dimensión(175, 100));
JLabel etiqueta2 = new JLabel("Soy otra etiqueta",JLabel.CENTER);
etiqueta2.setPreferredSize(new Dimensión(175, 100));
panel.add(etiquetal, BorderLayout.NORTH);
panel.add(etiqueta2, BorderLayout.SOUTH);
ventana.getContentPane().add(panel, BorderLayout.CENTER);
ventana.pack();
ventana.setVisible(true);
}
}
Código fuente 134

Se trata simplemente de añadir dos etiquetas a un panel (JPanel) y añadir este panel al panel de
contenido de una ventana (JFrame), el resultado se puede apreciar en la Figura 78.

178
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

Figura 78

La clase JPanel hereda de la clase JComponent, y debido a ello permite utilizar una nueva
funcionalidad ofrecida por Swing, los bordes.

Cada objeto de la clase JComponent puede tener uno o más bordes. Los bordes no son realmente
componentes, sino que se utilizan para delimitar visualmente una serie de componentes de otros. Para
asignar un borde a un componente, en este caso un objeto de la clase JPanel, se utiliza el método
setBorder().

Para crear los distintos bordes que ofrece Swing se suele utilizar la clase BorderFactory. Esta clase
ofrece un gran número de métodos que permiten crear distintos tipos de bordes: de líneas, elevados,
hundidos, marcados, con títulos, una combinación de dos bordes, etc.

En el Código fuente 135 se puede observar como se asigna distintos bordes a distintos paneles dentro
de una ventana.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Panel{
public static void main(String s[]) {
JFrame ventana = new JFrame("Ventana Sencilla");
ventana.getContentPane().setLayout(new GridLayout(7,1));
((JPanel)ventana.getContentPane()).setBorder( BorderFactory.createEmptyBorder(10,10,10,10));
JPanel panell=new JPanel();
JLabel etiquetal = new JLabel("Borde tipo línea",JLabel.CENTER);
panell.setBorder(BorderFactory.createLineBorder(Color.black));
panell.add(etiquetal);
ventana.getContentPane().add(panell);
JPanel panel2=new JPanel();
JLabel etiqueta2 = new JLabel("Borde elevado",JLabel.CENTER);
panel2.setBorder(BorderFactory.createRaisedBevelBorder());
panel2.add(etiqueta2);
ventana.getContentPane().add(panel2);
JPanel panel3=new JPanel();
JLabel etiqueta3 = new JLabel("Borde hundido",JLabel.CENTER);
panel3.setBorder(BorderFactory.createLoweredBevelBorder());
panel3.add(etiqueta3);
ventana.getContentPane().add(panel3);
JPanel panel4=new JPanel();

179
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

JLabel etiqueta4 = new JLabel("Borde decorado",JLabel.CENTER);


panel4.setBorder(BorderFactory.createMatteBorder(5,5,5,5,Color.red)]
panel4.add(etiqueta4);
ventana.getContentPane().add(panel4);
JPanel panel5=new JPanel();
JLabel etiqueta5 = new JLabel("Borde con título",JLabel.CENTER);
panel5.setBorder(BorderFactory.createTitledBorder(
BorderFactory.createLineBorder(Color.blue),"Titulo"));
panel5.add(etiqueta5);
ventana.getContentPane().add(panel5);
JPanel panel6=new JPanel();
JLabel etiqueta6 = new JLabel("Borde grabado",JLabel.CENTER);
panel6.setBorder(BorderFactory.createEtchedBorder()) ;
panel6.add(etiqueta6);
ventana.getContentPane().add(panel6);
JPanel panel7=new JPanel();
JLabel etiqueta7 = new JLabel("Borde compuesto",JLabel.CENTER);
panel 7.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(Color.yellow), BorderFactory.createRaisedBevelBorder()));
panel7.add(etiqueta7);
panel7.setPreferredSize(new Dimensión(175,50));
ventana.getContentPane().add(panel7);
ventana.pack();
ventana.setVisible(true);
}
}
}
Código fuente 135

Y el resultado se muestra en la Figura 79.

El Código fuente 135 merece una serie de comentarios. El primero de ellos es referente al tipo de
borde utilizado en el panel de contenido, como se puede observar al recuperar el panel de contenido
para asignarle un borde vacío se ha tenido que hacer un "cast" con la clase JPanel, este borde vacío se
ha utilizado para crear un margen entre el panel de contenido y el contenedor, en este caso una
instancia de la clase JFrame.

180
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

Figura 79

Al panel de contenido de la ventana se le ha asignado un gestor de diseño GridLayout con siete filas y
una única columna. Algunos de los métodos de la clase BorderFactory se encuentran sobrecargados,
para permitir una mayor personalización de los distintos tipos de bordes que queremos asignar.

A cada panel se le ha asignado un borde distinto y se le ha añadido una etiqueta (JLabel) con la
descripción del tipo de borde correspondiente.

JTabbedPane
Gracias a este contenedor intermedio podemos tener distintos componentes, normalmente otros
paneles, compartiendo un mismo espacio. El usuario puede visualizar los componentes que desea ver
seleccionando la pestaña correspondiente.

Para crear un contenedor de este tipo primero debemos instanciar el objeto correspondiente de la clase
JTabbedPane, luego se van creando los distintos componentes y se van añadiendo al contenedor
mediante el método addTab().

Antes de seguir con esta nueva clase vamos a verla en acción mediante un sencillo ejemplo. El
ejemplo consiste simplemente en un objeto JTabbedPane al que se le van añadiendo distintos paneles,
cada uno con sus componentes. El código se puede ver en el Código fuente 136.

import java.awt.*;
import java.awt.event.*; import javax.swing.*;
public class PanelTab{
public static void main(String s[]) {
JFrame ventana = new JFrame("Ventana Sencilla");
Imagelcon icono = new Imagelcon("icono.gif");

181
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

JTabbedPane panelTab = new JTabbedPane();


//tratamiento de eventos para el cierre de la ventana ventana.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e) { System.exit(0);
}
}
//se van creando paneles con componentes y se añaden al objeto JtabbedPane
JPanel panell=new JPanel();
panel1.add(new JButton("Botón",icono));
//se crea una nueva pestaña con el nuevo componente
panelTab.addTab("Uno",icono,panel1,"Soy la primera pestaña");
panelTab.setSelectedlndex(0);
JPanel panel2=new JPanel();
panel2.add(new JLabel("Soy una etiqueta",JLabel.CENTER));
panelTab.addTab("Dos",icono,panel2,"Soy la segunda pestaña");
JPanel panel3=new JPanel();
panel3.add(new JLabel("Soy otra etiqueta",JLabel.CENTER));
panel3.setBorder(BorderFactory.createLineBorder(Color.red));
panelTab.addTab("Tres",icono,panel3,"Soy la tercera pestaña");
JPanel panel4=new JPanel();
panel4.add(new JToggleButton("Otro botón",icono));
panelTab.addTab("Cuatro",icono,panel4,"Soy la cuarta pestaña");
JPanel panel5=new JPanel();
pane15.add(new JSlider(JSlider.HORIZONTAL,0,30,10));
panelTab.addTab("Cinco",icono,panel5,"Soy la última pestaña");
//se le da un tamaño al contenedor de pestañas
panelTab.setPreferredSize(new Dimensión(400,200));
//se añade a la ventana
ventana.getContentPane().add(panelTab);
ventana.pack();
ventana.setVisible(true);
}
Código fuente 136

Y el resultado de este código se puede apreciar en la Figura 80.

Figura 80

Si se prueba el ejemplo anterior se puede comprobar que no se ha escrito ningún código para realizar
el tratamiento de eventos, la clase JTabbedPane realiza este tratamiento (mostrar los componentes de
la pestaña seleccionada) de forma automática.

182
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

En el ejemplo se ha utilizado un constructor de la clase JTabbedPane que no utiliza ningún parámetro,


pero existe otro constructor que permite, mediante una constante que recibe como parámetro,
especificar la localización de las pestañas. Estas constantes se encuentran definidas en la clase
JTabbedPane y son las siguientes TOP, BOTTOM, LEFT y RIGHT. Así si modificamos el ejemplo
anterior cambiando el constructor utilizado para el panel JTabbedPane mediante la línea de código que
aparece en el Código fuente 137.

JTabbedPane panelTab = new JTabbedPane(JTabbedPane.BOTTOM);


Código fuente 137

Obtenemos el resultado que vemos en la Figura 81.

Figura 81

Para añadir una nueva pestaña ya sabemos que debemos utilizar el método addTab(), este método
presenta las siguientes versiones:

• addTab(String texto, Component componente): el primer argumento indica el texto que va a


parecer en la pestaña y el componente que va a contener.

• addTab(String texto, Icón icono, Component componente): en este caso además se indica el
icono que se va a mostrar en la pestaña.

• addTab(String texto, Icón icono, Component componente, String ayuda): en la última versión
del método addTab() se permite especificar el texto que aparecerá a modo de ayuda (tooltip)
cuando situemos el puntero del ratón sobre la pestaña.

En el ejemplo se ha utilizado el método setSelectedIndex() para indicar la pestaña que por defecto se
encuentra seleccionada, que será la que mostrará sus componentes. Las pestañas comienzan a
numerarse en cero.

Para manipular las pestañas la clase JTabbedPane ofrece los siguientes métodos:

• insertTab(String texto, Icón icono, Component componente, String ayuda, int índice): inserta
una nueva pestaña en la posición indicada por el parámetro índice.

• removeTabAt(int índice): elimina la pestaña cuya posición coincida con la indicada.

• remove (Component componente): elimina la pestaña que contenga el componente


especificado como argumento.

• removeAll(): elimina todas las pestañas.

183
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

• int indexOfTab(String texto): devuelve el índice de la pestaña que posea el texto indicado por
parámetro.

• int getSelectedIndex(): devuelve el índice de la pestaña seleccionada actualmente.

También es posible modificar la apariencia de las pestañas del panel JTabbedPane. Podemos indicar el
icono que va a mostrar la pestaña según se encuentre habilitada o deshabilitada, también el color de
fondo y el del texto de la pestaña.

Así si una vez creado el panel de nuestro ejemplo añadimos las líneas de código que se muestran
en el Código fuente 138 y obtenemos el resultado que aparece en la Figura 82.

//color de fondo cuando no está seleccionada la pestaña


panelTab.setBackgroundAt(0,Color.red);
//color del texto
panelTab.setForegroundAt(0,Color.green);
Imagelcon otrolcono = new Imagelcon("icono2.gif");
//icono que se muestra cuando la pestaña está desactivada
panelTab.setDisabledlconAt(0,otrolcono);
//se modifica el título
panelTab.setTitleAt(2,"Otro texto");
JPanel panelNuevo=new JPanel();
pane1Nuevo.add(new JTextArea(5,30));
//se cambia el componente que posee la pestaña
panelTab.setComponentAt(3,panelNuevo);
Código fuente 138

Figura 82

Curioso resultado ya que no se muestra el icono que se utiliza para indicar que la pestaña está
deshabilitada.

Si utilizamos cualquiera de los métodos anteriores ,que tiene como parámetro el índice de la pestaña, y
la pestaña no existe se producirá una excepción.

JToolBar
Esta clase representa una barra de herramientas, normalmente este tipo de contenedor va a contener
botones con iconos dentro de una fila o columna. Estos botones cumplen las mismas funciones que las
opciones de menú.

184
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

Por defecto el usuario puede arrastrar la barra de herramientas y situarla en los diferentes bordes del
contenedor o bien como una ventana independiente. Para que este funcionamiento de arrastre de la
barra sea correcto, el contenedor en el que se sitúa la barra de herramientas debe tener un gestor de
diseño BorderLayout. Normalmente la barra de herramientas se añade en el norte del gestor de diseño
y el componente al que afecta en el centro, no debe existir ningún componente más en el centro del
contenedor.

En el Código fuente 139 se puede observar como se utiliza un objeto de la clase JToolBar. En nuestro
caso vamos a tener una ventana (JFrame) que va a tener un panel de contenido al que se va a añadir la
barra de herramientas (JToolBar) y un área de texto (JTextArea). Como se puede ver la barra de
herramientas puede contener otros tipos de componentes, no sólo botones.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class BarraHerramientas{
public static void main(String s[]) {
JFrame ventana = new JFrame("Ventana con barra de herramientas");
//tratamiento de eventos para el cierre de la ventana
ventana.addWindowLi stener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
//iconos
Imagelcon iconol=new Imagelcon("iconol.gif");
Imagelcon icono2=new Imagelcon("icono2.gif");
Imagelcon icono3=new Imagelcon("icono3.gif");
//botones
JButton botonl=new JButton(iconol);
JButton boton2=new JButton(icono2);
JButton boton3=new JButton(icono3);
//lista con elementos
JComboBox combo=new JComboBox();
combo.addltem("uno");
combo.addltem("dos");
combo.addltem("tres");
//caja de texto
JTextField caja=new JTextField("caja de texto");
//barra de herramientas
JToolBar barra=new JToolBar();
//se añaden los botones
barra.add(botonl);
barra.add(boton2);
barra.add(boton3);
//se añade el separador a la barra de herramientas
barra.addSeparator();
barra.add(combo);
barra.add(caja);
//se añade la barra al panel de contenido
ventana.getContentPane().add(barra,BorderLayout.NORTH);
//se crea un área de texto
JTextArea areaTexto = new JTextÁrea(5,30);
//se añade a un panel de scroll

185
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

JScrollPane scrollPane = new JScrollPane(areaTexto);


//se añade el panel de scroll al panel de contenido
ventana.getContentPane().add(scrollPane,BorderLayout.CENTER);
//se asigna un tamaño preferido a la vetana
((JPanel)ventana.getContentPane()).setPreferredSize(new Dimensión(400, 100));
ventana.pack();
ventana.setVisible(true);
Código fuente 139

El resultado se muestra en la Figura 83.

Figura 83

Como se puede comprobar en el código anterior, para añadir un separador a la barra de herramientas
se utiliza el método addSeparator(). Si queremos que la barra de herramientas permanezca fija se
puede lanzar sobre el objeto de la clase JToolBar el método setFloatable() pasando como argumento el
valor false.

Para posicionar los distintos elementos que contiene, la clase JToolBar utiliza el gestor de diseño
BoxLayout, que veremos más adelante en el apartado dedicado al mismo.

JLayeredPane
Este contenedor ofrece una tercera dimensión que permite posicionar los componentes que contiene
especificando una profundidad. La profundidad de un determinado componente se especifica mediante
un entero, cuanto mayor sea este entero mayor será la profundidad del componente correspondiente. Si
los componentes que contiene el panel de capas se superponen los componentes que se encuentran a
una mayor profundidad se muestran encima de los de una menor profundidad.

Vimos que los contenedores de alto nivel de Swing contienen un panel de raíz que a su vez contiene
un panel de capas (layered pane), normalmente no se suele utilizar el JLayeredPane del JRootPane,
sino que se crea un objeto JLayeredPane distinto para utilizarlo dentro de otro panel. Esto mismo
ocurre en nuestro ejemplo, que se sitúa un objeto de la clase JLayeredPane dentro del panel de
contenido de una ventana (JFrame).

Para añadir un componente a un JLayeredPane se utiliza el método add(), en este método se debe
indicar la profundidad del componente, es decir, la capa en la que se encuentra. En el siguiente
ejemplo se van añadiendo a una instancia de la clase JLayeredPane etiquetas con color de fondo a
distintas profundidades. Veamos el Código fuente 140.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class PanelCapas{
static private String [] textosCapa = { "Amarillo(0)", "Magenta (1)", "Azul (2) " , "Rojo (3)" , "Verde (4)" };
static private Color [] coloresCapa = { Color.yellow. Color.magenta, Color.blue, Color.red, Color.green };
public static void main(String s[]) {
JFrame ventana = new JFrame("Ventana con panel de capas");

186
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

JLayeredPane panelCapas=new JLayeredPane();


//tratamiento de eventos para el cierre de la ventana
ventana.addWindowLi stener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
//punto de origen
Point origen = new Point(10, 20);
//separación entre etiquetas
int separación = 35;
//se van creando las etiquetas de color a distinta profundidad
for (int i = 0; i < textosCapa.length; i++) {
JLabel etiqueta = creaEtiqueta(textosCapa[i],coloresCapa[i],origen);
//se añade la etiqueta al panel de capas
panelCapas.add(etiqueta,new Integer(i));
origen.x += separación;
origen.y += separación;
}
//se indica un tamaño para le panel
panelCapas.setPreferredSize(new Dimensión(300, 310));
//se añade el panel creado al panel de contenido de la ventana
ventana.getContentPane().add(panelCapas);
ventana.pack();
ventana.setVisible(true) ;
}
//método para la creación de etiquetas con un texto y un color en un punto de origen.
private static JLabel creaEtiqueta(String texto,Color color,Point origen) {
JLabel etiqueta = new JLabel(texto);
//se alinea el texto en la etiqueta
etiqueta.setVerticalAlignment(JLabel.TOP);
etiqueta.setHorizontalAlignment(JLabel.CENTER);
etiqueta.setOpaque(true);
etiqueta.setBackground(color);
//se asigna un borde a la etiqueta
etiqueta.setBorder(BorderFactory.createLineBorder(Color.black));
etiqueta.setBounds(origen.x, origen.y, 140, 140);
return etiqueta;
}
}
Código fuente 140

El aspecto de esta ventana es el de la Figura 84

187
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

Figura 84

Como se puede comprobar a la vista del código se han creado dos arrays que contienen por un lado los
textos de las etiquetas y por otro los colores de las etiquetas. Se ha utilizado un bucle for para ir
recorriendo estos arrays y crear las etiquetas mediante el método crearEtiqueta(). Como se puede ver
el método y los atributos utilizado son estáticos, ya que los utilizamos directamente en el método
main() si lanzarlos sobre una instancia de una clase.

Dentro de una capa, es decir, a una profundidad determinada, se puede especificar la posición de un
componente. Es posible por lo tanto definir la posición de un componente respecto al resto de
componentes dentro de la misma capa, para ello existe una versión del método add() que posee un
tercer parámetro para indicar esta posición dentro de la capa.

El valor de esta posición va desde -1 hasta n-1, dónde n es el número de componentes dentro de la
capa. Al contrario que las capas, cuanto menor es el número mayor es la profundidad del componente
dentro de la capa. Utilizar -1 es equivalente a utilizar n-1, indica la posición más en el fondo. Si
utilizamos 0 el componente se encontrará por encima del resto.

Si al ejemplo anterior le añadimos las líneas que muestra el Código fuente 141, una vez creadas las
etiquetas en las distintas capas.

Imagelcon icono = new Imagelcon("imagen.gif");


JLabel nuevaEtiqueta=new JLabel(icono);
nuevaEtiqueta.setBounds(180,75,icono.getlconWidth(),icono.getlconHeight());
panelCapas.add(nuevaEtiqueta,new Integer(2),0);
Código fuente 141

Lo que se hace es añadir una nueva etiqueta con un icono en la capa 2 de modo que quede por encima
de la etiqueta de color que ya existía en esa misma capa. El nuevo aspecto del panel de capas es el que
aparece en la Figura 85.

188
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

Figura 85

También es posible mover un componente de una capa a otra, para ello se utiliza el método setLayer().
Así si queremos mover la etiqueta con el icono a la capa 4 escribiremos lo que indica el Código fuente
142.

panelCapas.setLayer(nuevaEtiqueta,4,0);
Código fuente 142

El último argumento del método setLayer() es la posición del componente dentro de la nueva capa.

Para mover un componente dentro de una capa a la primera posición se utiliza el método
moveToFront(), y para enviarlo al fondo el método moveToBack(), ambos métodos tiene como
parámetro el componente al que se quiere cambiar de posición dentro de una capa. Si utilizamos el
método moveToBack() en nuestro código anterior como indica el Código fuente 143, el nuevo aspecto
del ejemplo es el de la Figura 86.

panelCapas.moveToBack(nuevaEtiqueta);
Código fuente 143

Con este último tipo de contenedor intermedio damos por terminado este apartado y este capítulo, en
el siguiente capítulo seguimos tratando componentes Swing, en este caso los componentes atómicos, y
también veremos otras aportaciones de Swing.

189
11. Interfaces de usuario en Java: componentes Swing / contenedores DFSI

Figura 86

190

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