Despliegues (Layouts)



 

Despliegues

Un despliegue es un objeto de la clase Layout (del paquete java.awt). Los contenedores tienen un método setLayout(Layout l) con el que se les puede asignar cualquier despliegue. La finalidad de los despliegues es facilitar al programador el trabajo de acomodar los componentes gráficos. En esta unidad se presentan cinco despliegues que son los más fáciles de utilizar: BorderLayout, FlowLayout, GridLayout, CardLayout y GridBagLayout. Estos despliegues pueden combinarse en diversos contenedores para obtener una gran variedad de interfaces gráficas, como puede verse en los ejemplos al final de esta sección.

Los primeros tres despliegues tienen dos virtudes importantes: la sencillez y la automatización. El último tiene como principal virtud la flexibilidad. Todos están diseñados para realizar cierta presentación automáticamente y sin necesidad de colocar cada componente exactamente en una posición numérica o manualmente, como suele hacerse en otros lenguajes o en entornos de programación visual. Pero antes de presentar los despliegues conviene estudiar cómo se pueden acomodar componentes sin usar despliegues, o lo que es igual, usando el despliegue nulo.

 

Layout null

Los componentes pueden colocarse exactamente donde el programador lo decida si en lugar de usar uno de los despliegues predeterminados aplica el despliegue nulo o Layout null (setLayout(null)) y define la posición y dimensiones de cada componente con el método

setBounds(int left,int top,int width,int height)

de la clase Component. Este sistema tiene el inconveniente de que la presentación no se ajusta automáticamante cuando se cambian las dimensiones del contenedor o la ventana, pero en muchas ocasiones es útil y además cuando el programador quiere controlar todos los detalles no hay mejor opción.

Los generadores visuales de interfaces de usuario, como los que ofrecen Visual J++ o JBuilder, permiten acomodar manualmente cada componente exactamente donde uno lo desea. En realidad lo único que hacen es utilizar el null Layout y permitir al programador colocar los componentes con el ratón en lugar de tener que calcular las coordenadas y el tamaño. De cualquier manera, lo que hacen es usar también el método setBounds.

Este sistema puede ser muy útil cuando lo que se diseña es una interfaz para una aplicación que aparecerá en pantalla con un tamaño fijo. Sin embargo, si se quiere que la apariencia de la intefaz se ajuste a diferentes tamaño del contenedor, es más conveniente utilizar los otros despliegues de Java.

El siguiente applet muestra cómo puede crearse una interfaz de usuario usando el Layout null. Para facilitar la comprensión los textos de los diversos componentes coinciden con los parámetros que se usaron para fijar su localización y tamaño en la llamada al método setBounds.

Como puede apreciarse, este sistema no es muy complicado, aunque puede ser laborioso. Tiene como principal ventaja que da total control al programador, pero puede producir programas de muy difícil mantenimiento. También tiene el defecto de que si se quiere cambiar el tamaño del contenedor (el applet o la ventana), será necesario modificar el código (aunque esto lo podría evitar una buen programación en la que los cálculos del tamaño y posición de los componentes dependiera del tamaño del contenedor, cosa que es bastante difícil de hacer).

En general para programas sencillos resulta cómodo utilizar los otros despliegues que se describen en esta unidad.

 

GridLayout

El más sencillo de los despiegues (aparte de null) es GridLayout. Tiene dos constructores. El más simple es:

GridLayout(int filas,int columnas)

Cuando a un Panel (o cualquier otro contenedor) se le aplica este despliegue mediante

setLayout(new GridLayout(filas,columnas)

habrá que agregarle filas*columnas componentes y éstos se van acomodando de izquierda a derecha y de arriba a abajo (ver preImposible.java al final de la sección). El resultado son filas*columnas componentes del mismo tamaño que se ajusta a que quepan exactamente en el lugar que se les ha asignado. Esto se logra sin que el programador tenga que hacer cálculos o acomodar manualmente cada componente. En muchas aplicaciones se utiliza GridLayout con una sola fila o una sola columna (ver las líneas superior e inferiro de preDibuja.java al final de la unidad).

GridLayout tiene otro constructor que permite definir la separación (en pixels) ente los componentes, misma que es cero con el primer constructor. Así, por ejemplo

crea un desplieque de 3 filas y 4 columnas donde los componentes quedan a dos pixels de separación, como muestra este ejemplo:

    setLayout(new GridLayout(3,4,2,2);
    for (int i=0;i<3*4;i++) {

      add(new Button(Integer.toString(i+1)));

    }

 

BorderLayout

BorderLayout crea cinco espacios donde acomodar componentes o paneles. La localización de estos espacios queda descrita por cadenas con los nombres de "Center" y los cuatro puntos cardinales: "North", "South", "East" y "West". Por ejemplo la construcción de la izquierda crea el despliegue de la derecha:

setLayout(new BorderLayout());
add("North",new TextField("Norte"));
add("South",new TextField("Sur"));
add("East",new Button("Este"));
add("West",new Button("Oeste"));
Label lbl=new Label("Centro");
lbl.setAlignment(Label.CENTER);
add("Center",lbl);
,

BorderLayout tiene otro constructor BorderLayout(int seph,int sepv) con el que se pueden definir las separaciones vertical y horizontal entre los componentes que aparecerán en las cinco zonas.

BorderLayout es muy útil como despliegue inicial de un programa. En sus cinco regiones pueden luego colocarse contenedores con otros despliegues, por ejemplo se puede poner al norte o al sur un contenedor con un despliegue de tipo GridLayout, como se hace abajo en los ejemplos preActionApplet, preImposible y preDibuja.

 

FlowLayout

Los dos despliegues anteriores (GridLayout y BorderLayout) controlan el tamaño de los componentes adecuándolo al espacio que se les haya asignado. En cambio FlowLayout "respeta" el tamaño de los componentes y trata de acomodarlos uno tras otro dejando cierto espacio entre uno y el siguiente. Por supuesto en este caso a veces los componentes no caben en el espacio que se les ha asignado y puede ocurrir que algunos no se deplieguen.

El ejemplo siguiente acomoda varios componentes en un applet con un despliegue de tipo FlowLayout.

setLayout(new FlowLayout());
add(new TextField("texto"));
add(new TextField("...",8));
add(new Button("botón"));
add(new Label("etiqueta"));
add(new Checkbox("interruptor"));
Choice ch=new Choice();
ch.add("uno"); ch.add("dos"); ch.add("tres");
add(ch);
add(new TextArea(5,10));
CheckboxGroup g=new CheckboxGroup();
add(new Checkbox("si",g,true));
add(new Checkbox("no",g,false));
add(new Checkbox("tal vez",g,false));
List l=new List(4,true);
l.add("one"); l.add("two"); l.add("three");
l.add("four"); l.add("five"); l.add("six");
add(l);
,

FlowLayout es el despliegue que todo panel tiene por defecto.

Hay otros dos constructores aparte del que se utiliza en el ejemplo.

FlowLayout(int align)

que permite elegir si los componentes se acomodan alineados a la izquierda, centrados o alineados a la derecha, según se pase como parámetro una de las constantes: FlowLayout.LEFT, FlowLayout.CENTER o FlowLayout.RIGHT respectivamente. Otro constructor:

FlowLayout(int align,int seph,int sepv)

permite además elegir la separación entre los componentes. El valor por defecto de seph y sepv es de 5 pixels.

El tamaño de cada componente dentro de un despliegue de tipo FlowLayout depende del tipo de letra que se le haya asignado o tenga por defecto. Los tamaños se ajustan para que las cadenas que en ellos aparecen queden bien presentadas. Los campos y cuadros de texto tienen constructores con los que se puede definir su ancho (en el caso de los campos de texto) y su alto y ancho (en el caso de los cuadros o áreas de texto). Las unidades para medir esto son "filas" para el alto y "columnas" para el ancho. En la mayoría de los intérpretes y navegadores el número de columnas se calcula utilizando la letra más ancha de la fuente asignada al componente, pero en otros se usa un promedio, por lo cual el ancho de un campo de texto suele cambiar de un navegador a otro.

Advertencia: Para agregar una pizarra (Canvas) a un contenedor con despliegue de tipo FlowLayout es necesario llamar al método Canvas.setSize(int ancho,int alto) para determinar el tamaño de la pizarra, de otra manera no aparece porque su tamaño por defecto es 0x0. No conviene agregar barras de desplazamiento a un contenedor con despliegue FlowLayout porque no se puede controlar su aspecto. Se recomienda que para agregar barras de desplazamiento, se utilice BorderLayout agregando las barras horizontales al norte o al sur y las barras verticales al este o al oeste.

 

CardLayout

El CardLayout es un despliegue especial que poco tiene que ver con los otros que se presentan en esta unidad. Su objetivo es desplegar sólo un componente o contenedor a la vez pero teniendo la posibilidad de desplegar otros en otras circunstancias. Puede pensarse que el CardLayout consta de tarjetas (cards) todas del mismo tamaño (el tamaño del contenedor) que están unas detrás de otras y sólo puede verse la que está al frente.

El siguiente ejemplo muestra un applet con un BorderLayout en el que al centro se ha agregado un panel que tiene un CardLayout al que se han agragado a su vez varias pizarras de distintos colores, cada una con el nombre igual a su color. El grupo de interruptores que aparece arriba permite elegir la pizarra del color deseado, lo cual se logra haciendo que se despliegue la "tarjeta" correspondiente..

El alumno debe estudiar detenidamente el código de este applet. Observará primero que el grupo de interruptores se agrega en un panel al "norte" del applet en el que se ha puesto un GridLayout. Luego verá que al "centro" del applet se agrega un panel CP que se ha declarado como una variable de la clase para poder hacer referencia a ella en otros métodos de la clase. Al panel CP se le pone un CardLayout llamado CL, que también se ha declarado como una variable de la clase. Finalmente se agragan a CP las pizarras de colores asociándoles el nombre del color. Para desplegar una de las pizarras que son los "cards" o "tarjetas" del CardLayout, hay que llamar al método show(Container C,String cardName) de CL, concretamente, para desplegar la i-ésima tarjeta hay que llamar a CL.show(CP,colorname[i]). El nombre con que se ha registrado la tarjeta al agregarse al panel es el que permite identificarla para desplegarla. Es importante remarcar que el  método show que se usa para desplegar una tarjeta es un método del CardLayout CL y requiere como parámetros el contenedor CP y el nombre de la tarjeta, es por esto que tanto el CardLayout CL como el panel CP deben ser variables de la clase.

La interfaz ItemListener y el método correspondiente itemStateChanged(ItemEvent e) que se usan en este ejemplo para hacer funcionar el applet se estudian en la unidad 4 sobre eventos.

 

GridBagLayout

Existe otro tipo de despliegue más flexible aunque más complicado de utilizar. Se trata del GridBagLayout.  Funciona de manera parecida a las tablas en HTML. GridBagLayout permite acomodar componentes en filas y columnas, pero cada fila y cada columna pueden tener un tamaño diferente y además un componente puede ocupar más de una casilla. Para lograr acomodar todo como el programador desea es necesario especificar algunos parámetros para cada componente que se agrega. Esto se hace utilizando un objeto de la clase GridBagConstraints a través del método

setConstraints(Component comp, GridBagConstraints cons)

del despliegue. Éstas son la variables de GridBagConstraints y sus significados:

int anchor punto fijo ante cambios de tamaño
int fill cómo debe crecer
int gridheight número de filas que abarca
int gridwidth número de columnas que abarca
int gridx número de columna donde empieza
int gridy número de fila donde empieza
int weightx peso en la distribución del espacio horizontal sobrante
int weighty peso en la distribución del espacio vertical sobrante
int ipadx espacio adicional horizontal dentro de la celda
int ipady espacio adicional vertical dentro de la celda
Insets insets objeto que especifica los márgenes

En la mayoría de las aplicaciones basta especifica solamente gridx,gridy,gridwidth y gridheight y dejar los demás parámetros con sus valores por defecto.

Para especificar int anchor se utilizan las siguientes constantes de GridBagConstraints: CENTER, EAST, NORTH, NORTHEAST, NORTHWEST, SOUTH, SOUTHEAST, SOUTHWEST y WEST. Para especificar int fill se utilizan las siguientes constantes de GridBagConstraints: HORIZONTAL, VERTICAL, BOTH y NONE. Finalmente, hay dos constantes útiles para las variables de posición y tamaño: RELATIVE y REMAINDER. La primera sirve para especificar que el componente es el penúltimo en su fila o columna y REMAINDER indica que es el último.

En los ejemplos siguientes se utilizan despliegues de tipo GridBagLayout. El alumno debe estudiar cuidadosamente cada ejemplo y hacer modificaciones en ellos para comprender el significado preciso de cada variable de la clase GridBagConstraints.

El primer ejemplo muestra cómo se pueden acomodar componentes ocupando más de una casilla usando gridx, gridy, gridwidth y gridheight:

El segundo ejemplo ilustra el uso de las variables anchor, fill e ipadx:

El uso de las variables weightx y weighty se ilustra en el tercer ejemplo:

Como puede aprecierse en estos ejemplos el GridBagLayout es muy flexible. Su utilización es todo un arte en el que algunos programadores de Java son expertos y pueden lograr cualquier cosa.

 

Ejemplos de aplicación

El alumno deberá crear varios ejemplos usando los diferentes despliegues para adquirir soltura en su aplicación. Los ejercicios de este capítulo lo guiarán en esta tarea.

En los ejemplos que se presentan a continuación se utilizan repetidamente paneles, despliegues y componentes para lograr el aspecto que presenta cada uno. Son ejemplos preparativos para la Unidad 4 (de ahí el prefijo "pre" en los nombres). En esta lección sólo se presenta la parte visual de las interfaces de usuario mientras que en la lección 5 se convertirán en auténticas interfaces interactivas que responderán a los eventos generados por el usuario. Pero cada cosa a su tiempo. Aquí sólo se muestra cómo se crean y despliegan los componentes que vamos a necesitar en los programas de la Unidad 4.

En la tabla aparecen los despliegues a la izquierda y el código que los ha generado a la derecha. El alumno debe estudiar cuidadosamente cada ejemplo para desarrollar una intuición de lo que se puede lograr combinando despliegues y paneles auxiliares.

En la Unidad 4 estos ejemplos se convertirán en programas interactivos completos al agregar la detección y control de eventos.

preActionApplet servirá en la Unidad 4 para crear un applet en el que se pueden detectar eventos.

preImposible servirá en la Unidad 4 para crear un divertido juego.

preDibuja se convertirá en la Unidad 4 en un sencillo programa de dibujo.

Ejercicios