Swing y JFC (Java Foundation Classes)

Los paquetes Swing incluyen un controlador de distribuci�n de prop�sito geneal llamado BoxLayout. BoxLayout o bien situa los componenes uno encima d eotro (con el primer componente en la parte superior) o los situa en una delgada fila de izquierda a derecha - a nuestra eleci�n. Podr�amos pensar que es una versi�n m�s potente de FlowLayout. Aqu� tenemos una versi�n de un applet que usa un BoxLayout para mostrar una columna de componetes centrada.

Esta es una imagen del GUI del applet, para ejecutarlo, pulsa sobre ella y el applet aparecer� en una nueva ventana del navegador.

Creando uno o m�s contenedores de peso ligero que usen BoxLayout, podemos conseguir distribuciones m�s complejas para las que normalmente se usar�a GridBagLayout. BoxLayout tambi�n es �til en algunas situaciones donde podr�amos considerar la utilizaci�n de GridLayout o BorderLayout. Hay una gran diferencia entre BoxLayout y los controladores de distribuci�n existentes en el AWT, y es que BoxLayout respeta el tama�o m�ximo y el alineamiento X/Y de cada componente.

La siguiente figura muestra un GUI que usa dos ejemplares de BoxLayout. En la parte superior del GUI un boxlayout de arriba-a-abajo situa una etiqueta sobre un scroll pane. En la parte inferior del GUI, un boclayout de izquierda-a-derecha situa dos botones uno junto al otro. Un BorderLayout combina las dos partes del GUI y se asegura que cualquier exceso de espacio ser� entregado al scroll pane.

El siguiente c�digo, tomado de ListDialog.java, disribuye el GUI. Este c�digo est� en el constructor del di�logo, que est� implementadocomo una subclase de JDialog. Las l�neas en negrita inicializan los boxlayout y les a�aden los componentes.

JScrollPane listScroller = new JScrollPane(list);
listScroller.setPreferredSize(new Dimension(250, 80));
listScroller.setMinimumSize(new Dimension(250, 80));
listScroller.setAlignmentX(LEFT_ALIGNMENT);
...
//Lay out the label and scroll pane from top to bottom.
JPanel listPane = new JPanel();
listPane.setLayout(new BoxLayout(listPane, BoxLayout.Y_AXIS));
JLabel label = new JLabel(labelText);
listPane.add(label);
listPane.add(Box.createRigidArea(new Dimension(0,5)));
listPane.add(listScroller);
listPane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));

//Lay out the buttons from left to LEFT.
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.X_AXIS));
buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
buttonPane.add(Box.createHorizontalGlue());
buttonPane.add(cancelButton);
buttonPane.add(Box.createRigidArea(new Dimension(10, 0)));
buttonPane.add(setButton);

//Put everything together, using the content pane's BorderLayout.
Container contentPane = getContentPane();
contentPane.add(listPane, BorderLayout.CENTER);
contentPane.add(buttonPane, BorderLayout.SOUTH);

La primera l�nea en negrita crea el boxlayout de ariba-a-abajo y lo inicializada como el controlador de distribuci�n para el listPane. Los dos argumentos del constructor de BoxLayout son el contenedor que maneja y el eje sobre el que se van a distribuir los componente. Las tres siguiente l�neas en negrita a�aden la etiqueta y el scroll pane al contenedor, separ�ndolas con un �rea r�gida -- un componente invisible de peso ligero usado para a�adir espacio entre componentes. En este caso, el �rea r�gida no tiene anchura y pone exactamente 5 pixels entre la etiqueta y el scroll pane. Las �reas r�gidas se describen m�s tarde en Usar componentes invisibles como relleno.

El siguiente bloque de c�digo en negrita crea un boxlyout de izquierda-a-derecha y lo selecciona para contenedor buttonPane. Luego el c�digo a�ade dos botones al contenedor, usando un �rea r�gida de 10 pixels entre los botones. Para hacer que los botones sean situadas en el lado derecho de su contenedor, el primer componente a�adido al contenedor es glue. Este glue es un componente invisible de peso ligero que crece lo necesario para absrover cualquier espacio extra en su contenedor. Glue se describe en Usar componentes invisibles como relleno.

Como alternativa al uso de componentes invisibles, algunas veces podemos usar bordes vac�os para crear espacio alrededor de los componentes. Por ejemplo, el c�digo anterior usa bordes vac�os de 10 pixels entre todos los lados del dialog y sus contenidos, y entre las dos partes de los contenidos. Los bordes son completamente independientes de los controladores de distribuci�n. Son s�lo la forma en que los componentes Swing dibujan sus lados. Para m�s informaci�n puedes ver C�mo usar Borders.

No dejes que te asuste la longitud de esta p�gina. Probablemente podr�s usar BoxLayout con la informaci�n que ua posees. Si tienen problemas o quieres tomar ventaja de la potencia de BoxLayout puedes leerlo m�s tarde.

.�Caracter�sticas de BoxLayout

Como hemos dicho antes, un BoxLayout dsiribuye componentes de arriba-a-abajo o de ozquierda-a-derecha. Y esta distribuci�n tiene en cuentra los alineamientos y los tama�o m�nimo preferido y m�ximo de caa componente. En esta secci�n, hablaremos sobre la distribuci�n de arriba-a-abajo (eje Y). Los mismos conceptos se pueden aplicar a la distribuci�n de izquierda a derecha. Simplemente tenemos que sustituir X por Y, anchura por altura, etc.

Cuando un BoxLayout distribuye sus componentes de arriba a abajo, intenta dismiensionarlos a la altura preferida de cada uno de ello. Si la cantidad de espacio vertical no es ideal, el boxlayout intenta ajustar la altura de cada componente para quue los componente llener la cantidad de espacio disponible. Si embargo, los componentes podr�an no caber exactamente, ya que BoxLayout respeta las alturas m�nima y m�xima de cada componente. Cualquier espacio extra aparecer� en la parte inferior del contenedor.

Un BoxLayout de arriba-a-abajo intenta hacer que todos sus componentes tengan la misma anchura -- tan anchos como la anchura m�xima preferida. Si se fuerza el contenedor a ser m�s ancho que esto, el boxlayout intenta hacer todos los componentes tan anchos como el contenedor. Si los componentes no son de la misma anchura (debido a las restricciones del tama�o m�ximo o a que alguno de ellos tiene un alineamiento estricto a la izquierda a derecha), el alineamiento X entra en juego.

El alineamiento X afecta no s�lo a la posici�n relativa de los componentes, sino tambi�n a la localizaci�n de los componentes (como grupo) dentro del contenedor. Las siguiente figuras ilustran el alineamiento de componentes que tienen anchuras m�ximas restringidas.

En la primera figura, los tres componentes tienen un alineamiento X de 0.0 (Component.LEFT_ALIGNMENT). Esto significa que los lados izquierdos de los componentes deber�an estar alineados. Adem�s, significa que los tres componentes deben posicionarse tan a la izquierda de su contenedor como sea posible.

En la segunda figura, los tres componentes tiene un alineamiento X de 0.5 (Component.CENTER_ALIGNMENT). Esto significa que los centros de los componentes deben estar alineados, y que los contenedores deber�an situarse en el centro horizontal de su contenedor.

En la tercera figura, los componentes tienen un alineamiento X de 1.0 (Component.LEFT_ALIGNMENT). Puedes imaginar lo que esto significa para el alineamiento de los componetes y para su posici�n relativa dentro del contenedor.

Podr�amos preocuparnos por lo que suceder� cuando los tienen tama�os m�ximo restringidos y diferentes alineamientos X. La siguiente figura muestra un ejemplo de esto.

Como puedes ver, el lado izquierdeo con alineamiento X de 0.0 (Component.LEFT_ALIGNMENT) est� alineado con el centro del componente con el alineamiento X de 0.5 (Component.CENTER_ALIGNMENT), que est� alineado con el lado derecho del componente con el alineamiento X de 1.0 (Component.LEFT_ALIGNMENT). Los alineamientos mezclados como esto se discuten m�s adelante en Resolver problemas de Alineamiento.

�Qu� pasa si ning�n componente tiene una anchura m�xima? Bien, si todos los componentes tienen id�ntico alineamiento X, todos los componentes ser�n tan anchos como su contenedor. Si el alineamiento X es diferente, cualquier componente con alineamiento 0.0 (izquierda) o 1.0 (derecha) ser�n m�s peque�os. Todos los componentes con una alineamiento X intermedio (como el centro) ser�n tan anchos como su contenedor. Aqu� tenemos dos ejemplos.

Para conocer mejor BoxLayout, puedes hacer tus propios experimentos con BoxLayoutDemo.

Prueba esto:
  1. Compila y ejecuta BoxLayoutDemo. Los ficheros fuentes son BoxLayoutDemo.java y BLDComponent.java.
  2. Pulsa dentro de uno de los rect�ngulos

    As� es como se cambia el alineamiento X de los rect�ngulos.

  3. Pulsa el check box de la parte inferior de la ventana.

    Esta desactiva las restriciones de tama�o de todos los rect�ngulos.

  4. Agranda la ventana.

    Esto hace que el contenedor de los rect�ngulos sea m�s grande que la suma de los tama�o m�ximo preferidos de los rect�ngulos. El contenedor en un JPanel que tiene un borde rojo, por lo que puedes diferenciar donde est�n los laterales del contenedor.

.�Usar Componentes Invisibles como Relleno

Cada componente controlador por un BoxLayout se pega a sus vecinos. Si queremos tener espacio entre componentes podemos a�adir un borde vac�o a uno de los componentes o insertar componentes invisibles para proporcionar espacio. Podemos crear componentes invisibles con la ayuda de la clase Box.

La clase Box porporciona una clase interna Box.Filler que proporciona componentes invisibles. La clase Box proporciona m�todos de conveniencia para crear los tipos m�s comunes de rellenos. La siguiente tabla ofrece detalles sobre la creacci�n de componentes invisibles con Box y Box.Filler.

Tipo Restricciones de tama�o C�mo crearlo
�rea r�gida

  XXXXX
  XXXXX
  XXXXX
Box.createRigidArea(size)
glue horizontal
<- . ->
Box.createHorizontalGlue()

vertical
   ^
   |

   .

   |
   v
Box.createVerticalGlue()
Box.Filler personalizado

(seg�n se especifique)
new Box.Filler(minSize, prefSize, maxSize)

Aqu� podemos ver como se usa generalmente cada tipo de relleno.

�rea R�gida
Se usa cuando queremos un espacio de tama�o fijo entro dos componentes. Por ejmplo, para poner 5 pixels entre dos componentes en un box de izquierda-a-derecha podemos usar este c�digo
container.add(firstComponent);
container.add(Box.createRigidArea(new Dimension(5,0)));
container.add(secondComponent);

Without rigid area:        With rigid area.
-------------------        -------------------
|XXXXYYY          |        |XXXX     YYY     |
|XXXXYYY          |        |XXXX<--->YYY     |
|XXXXYYY          |        |XXXX     YYY     |
-------------------        -------------------
Nota: La clase Box proporciona otro tipo de relleno para poner espacio fijo entre componentes: (struts) un puntal vertical u horizontal. Desafortunadamente los puntales no tienen sus anchuras o alturas m�ximas (para puntales horizontales o verticales, respectivamente). Esto significa que si usamos un box horizontal dentro de un box vertical por ejemplo, el el box horizontal puede algunas veces convertirse demasiado alto. Por esta raz�n, recomendamos usar �reas r�gidas en vez de "struts".
Glue
Se usa para especificar donde deber�a ir el exceso de espacio en la distribuci�n. Piensa en ello como un goma semi-humeda -- extrechable y expandible, que s�lo toma el espacio que los dem�s componentes no utilizan. Por ejemplo, ponendo un glue horizontal entre dos componentes en un box de izquierda-a-derecha, podemos hacer que todo el espacio extra se quede entre los dos componentes en vez de a la derecha del contenedor. Aqu� puedes ver un ejemplo de ello.
container.add(firstComponent);
container.add(Box.createHorizontalGlue());
container.add(secondComponent);

Without glue:              With glue.
-------------------        -------------------
|XXXXYYY          |        |XXXX          YYY|
|XXXXYYY          |        |XXXX<-------->YYY|
|XXXXYYY          |        |XXXX          YYY|
-------------------        ------------------- 
Box.Filler personalizado
Usado para especificar un componente con los tama�os m�nimo, preeferido y m�ximo que querramos. Por ejemplo, para crear alg�n relleno en un boxlayout de izquierda-a-derecha que ponga al menos 5 pixels entre dos componentes y se asegure de que el contenedor tenga una altura m�nima de 100 pixels, podr�amos usar este c�digo.
container.add(firstComponent);
Dimension minSize = new Dimension(5, 100);
Dimension prefSize = new Dimension(5, 100);
Dimension maxSize = new Dimension(Short.MAX_VALUE, 100);
container.add(new Box.Filler(minSize, prefSize, maxSize));
container.add(secondComponent);

Without filler:            With filler.
-------------------        -------------------
|XXXXYYY          |        |        ^        |
|XXXXYYY          |        |XXXX    |     YYY|
|XXXXYYY          |        |XXXX<-------->YYY|
-------------------        |XXXX    |     YYY|
                           |        v        |
                           ------------------- 

.�Resolver Problemas de Alineamiento

Algunas veces pueden ocurrir dos tipos de problema de alineamiento con BoxLayout.

  • Un grupo de componentes que tienen el mismo alineamiento, pero queremos cambiar sus alineamientos para que se vean mejor. Por ejemplo, en lugar de tener la parte superior de un grupo de botones de izquierda-a-derecha en un l�nea, podr�amos querer alinear la parte inferior de los botones. Aqu� tenemos un ejeplo.
  • Dos o m�s componentes controlados por un BoxLayout tienen distinto alineamiento por defecto, lo que hace que est�n desalineados. Por ejemplo, como muestra la siguiente imagen, si una etiqueta y un contenedor est�n en un boxlayout de arriba-a-abajo, el lado izquierda de la etiqueta, por defecto, est� alineado con el centro del contenedor.

    De forma similar, si un bot�n y un contenedor est�n en un boxlayout de izquierda-a-derecha el lado superior del bot�n, por defecto, est� alineado con el centro del contenedor.

En general, todos los componentes controlados por un objeto BoxLayout de arriba-a-abajo deber�an tener el mismo alineamineto X. Similarmente, todos los componetes controlados por un Boxlayout de izquierda-a-derecha deber�an tener el mismo alineamiento Y. Podemos seleccionar el alineamiento X de un componente Swing llamando a su m�todo setAlignmentX. Una alternativa es sobreescribir el m�todo getAlignmentX en un subclase personalizada de la clase del componente. Se puede hacer lo mismo para el alineamiento Y con los m�todos setAlignmentY y getAlignmentY.

Aqu� hay un ejemplo, tomado de AlignmentDemo.java, de cambio de alineamiento Y de dos botones para la parte inferior de los botones est� alineada.

button1.setAlignmentY(Component.BOTTOM_ALIGNMENT);
button2.setAlignmentY(Component.BOTTOM_ALIGNMENT);

Como muestra la siguiente tabla, los botones, las etiquetas y los items de men� Swing tienen diferentes valores de alineamiento X que todos los dem�s componentes. De igual forma, los botones, los items de men� y las barras de herraientas tienen diferentes alineamientis Y que todos los dem�s componentes.

Componente Swing Alineamiento X por defecto Alineamineto Y por defecto
Buttons, menu items LEFT_ALIGNMENT TOP_ALIGNMENT
Labels LEFT_ALIGNMENT CENTER_ALIGNMENT
Tool bars CENTER_ALIGNMENT TOP_ALIGNMENT
Todos los dem�s componentes Swing CENTER_ALIGNMENT CENTER_ALIGNMENT

El programa AlignmentDemo.java ofrece ejemplos de c�mo corregir los problemas de alineamientos. Normalmente es tan senciilo como forzar a los botones y las etiquetas a que tengan alinamiento centrado. Por ejemplo.

label.setAlignmentX(Component.CENTER_ALIGNMENT);
...
button.setAlignmentY(Component.CENTER_ALIGNMENT);

.�Especificar Tama�os de Componentes

Como mencionamos antes, BoxLayout presta atenci�n a las peticiones de tama�o m�nimo, preferido y m�ximo del componente. Mientras estemos ajustando la distribuci�n, podr�amos necesitar modificar estos tama�os.

Algunas veces la necesidad de ajustar el tama�o es obvia. Por ejemplo, el tama�o m�ximo de un bot�n Swing es el mismo que su tama�o preferido. Si queremos que un bot�n se dibuje m�s ancho cuando haya espacio disponible, obviamente necesitaremos cambiar el tama�o m�ximo.

Sin embargo, alguna veces, la necesidad de ajustar el tama�o no es tan obvia. Podr�amos obtener resultados inesperdados con un boxlayout, y querr�mos saber por qu�. En este caso, lo mejor es tratar el problema como si fuera un problema de alineamiento en primer lugar. Si ajustar los alineamientos no ayuda, podr�amos tener un problema de tama�os. Lo discutiremos un poco m�s tarde.

Nota: aunque BoxLayout presta atenci�n al tama�o m�ximo de un componente, la mayor�a de los controladores de distribuci�n no lo hacen. Por ejemplo, su ponemos un bot�n en la parte SOUTH de un BorderLayout, el bot�n probablemente ser� m�s ancho que su tama�o preferido. Por otro lado BoxLayout, nunca hace un bot�n tan ancho como su tama�o preferido a menos que especificamente cambiemos su tama�o m�ximo.

Podemos cambiar los tama�os m�nimo, preferido y m�ximo de dos formas.

  • Llamando al m�todo setXxxSize apropiado (que est� definido por la clase JComponent). Por ejemplo.
    comp.setMinimumSize(new Dimension(50, 25)); 
    comp.setPreferredSize(new Dimension(50, 25)); 
    comp.setMaximumSize(new Dimension(Short.MAX_VALUE, 
                                      Short.MAX_VALUE)); 
    
  • Sobreescribiendo el m�todo getXxxSize apropiado. Por ejemplo.
    ./in a subclass of a Swing component class:
    public void getMaximumSize() {
        size = getPreferredSize();
        size.width = Short.MAX_VALUE; //[PENDING: specify Short or Integer?]
        return size;
    }
    

Si tenemos problemas con un boxlayout y hemos resuelto los problemas de alineamiento, el problema podr�a estar relacionado con el tama�o. Por ejemplo, si el contenedor controlador por el boxlayout est� tomando demasiado espacio, entonces uno o m�s componentes probablemente necesiten tener su tama�o m�ximo restringido.

Podemos usar dos t�cnicas para seguir la pista de los problemas de tama�o en un boxlayout.

  • A�adir un borde en el lado exterior del componente Swing en cuesti�n. Esto permitir� ver el tama�o real del componente. Por ejemplo.
    comp.setBorder(BorderFactory.createCompoundBorder(
                       BorderFactory.createLineBorder(Color.red),
                       comp.getBorder()));
    
  • Usar el viejo System.out.println para imprimir los tama�os m�nimo, preferido y m�ximo del componente y quiz�s sus l�mites.

.�El API de BoxLayout

Las siguiente tablas listan los m�todos y constructores m�s usados de BoxLayout y Box. El API para usar BoxLayut se divide en tres categor�as.

.�Crear objetos BoxLayout

M�todo o Constructor Prop�sito
BoxLayout(Container, int) Crea un ejemplar de BoxLayout que controla el Container especificado. El argumento entero especifica si los componentes deber�an distribuirse de izquierda-a-derecha (BoxLayout.X_AXIS) o de arriba-a-abajo (BoxLayout.Y_AXIS).
Box(int) Crea un Box -- un contenedor de peso ligero que usa BoxLayout con el alineamiento especificado (BoxLayout.X_AXIS o BoxLayout.Y_AXIS). Observa que un Box no es un JComponent -- est� implementado como una subclase de Container. Esto hace que sea tan ligero como sea posible, pero se pierde algunas caracter�sticas de JComponent como los bordes. Si queremios un sencillo JComponent como contenedor, debemos usar JPanel.
static Box createHorizontalBox() Crea un Box que distribuye sus componentes de izquierda-a-derecha.
static Box createVerticalBox() Crea un Box que distribuye sus componentes de arriba-a-abajo.

.�Crear Rellenos

M�todo o Constructor Prop�sito
Component createHorizontalGlue()

Component createVerticalGlue()

Component createGlue()

Crea un componente de peso ligero glue.
Component createHorizontalStrut()

Component createVerticalStrut()

Crea componente de peso ligero "strut" Nosotros recomendamos el uso de �reas r�gidas en vez de los struts.
Box.Filler(Dimension, Dimension, Dimension) Crea un componente de peso ligero con los tama�os m�nimo, preferido y m�ximo especificados (con los argumentos especificados en este orden).

.�Otros M�todos �tiles

M�todo Prop�sito
void changeShape(Dimension, Dimension, Dimension) (en Box.Filler) Cambia los tama�os m�nimo, preferido u m�ximo del recipiente del objeto Box.Filler. La distribuci�n cambiara de forma autom�tica.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP
ARTÍCULO ANTERIOR