Lección 04

Componentes y Diseño de Interfaces, parte a.

En esta lección se estudian los componentes gráficos de Java, los contenedores de componentes, los diferentes métodos de despliegue que Java ofrece para acomodar los componentes en los contenedores, las ventanas y los menús.

El paquete java.awt está formado principalmente por las clases que se estudian en esta lección. Sería imposible incluir todos los detalles de las clases de java.awt en un curso. Para programar usando el AWT de Java es necesario consultar frecuentemente la documentación.


Componentes.


Un componente gráfico es una clase derivada (o sea, una extensión) de la clase Component. Aquí se presentan los componentes más usados, con los nombres en castellano que usaremos durante el curso, un ejemplo de cada uno y el código que generó el ejemplo. El alumno debe estudiar cada ejemplo para aprender la manera de crear e inicializar los componentes.

Button

botón

Canvas

pizarra

Checkbox

interruptor

CheckboxGroup

grupo

Choice

selector

Label

etiqueta

List

lista

Scrollbar

barra de
desplazamiento

TextArea

cuadro de texto

TextField

campo de texto

Como puede verse en los ejemplos de la tabla, para colocar un componente en un applet, primero hay que definir una variable del tipo deseado, después hay que crear una instancia, luego configurarla y finalmente, agregarla al applet (o como veremos más adelante a un contenedor).

Los cuatro pasos pueden mezclarse y a veces en una sola instrucción se pueden dar dos o tres pasos. Por ejemplo:

realiza en dos líneas los cuatro pasos. En la primera línea se declara la variable, se crea una instancia y se configura parcialmente asignándole su contenido. En la segunda línea sólo se agrega el campo de texto al contenedor. Lo mismo puede hacerse así:

He aquí una construcción muy frecuente:

En este caso no se declara la variable, sólo se crea la etiqueta y se agrega en la misma línea al contenedor. Esto puede hacerse cuando no deseamos en el futuro modificar o utilizar la etiqueta y por tanto no hace falta conservar una referencia a ella.

El alumno debe observar que grupo, es decir CheckboxGroup, no es un componente sino que se construye como un conjunto de interruptores. Sólo uno de los interruptores de un grupo puede tener valor true. Hay una diferencia en la presentación gráfica de un interruptor que pertenece a un grupo (círculos) respecto a los independientes (cuadros).

El siguiente ejemplo muestra varios componentes. El alumno debe estudiar el código que los ha generado observando los diferentes constructores y los métodos que se han usado para lograr las diferentes configuraciones.

Las listas muestran cierto número de filas (por defecto 4). Si la lista tiene más elementos que filas, aparece una barra de desplazamiento que permite ver todo el contenido de la lista. Lo mismo ocurre cuando el contenido de un cuadro de texto no cabe en el rectángulo asignado al cuadro.

Component es una clase abstracta que tiene muchos métodos, pero no es necesario conocerlos todos para usar sus clases derivadas. Lo importante es conocer sus métodos más usados y éstos se pueden ver en los ejemplos anteriores y en los que se presentarán en esta misma lección.

Es importante aclarar algo sobre el tamaño de los componentes. El paquete awt fue diseñado para que sus componentes sean utilizados en combinación con despliegues (Layouts). La idea es que los componentes adquieran el tamaño que conviene según la forma en que el programador desea acomodarlos. Por este motivo no siempre es conveniente ni fácil fijar el tamaño de un componente. En la sección sobre despliegues se aclarará este tema.

En los ejemplos de las siguientes secciones de esta lección, se verán más casos de construcciones y configuraciones de componentes. La manera de aprender a usar y configurar componentes es mirando muchos ejemplos y haciendo otros con ayuda de la documentación del paquete java.awt.


Contenedores.


Un contenedor es una clase derivada de la clase Container. Los contenedores son componentes que tienen la capacidad de albergar otros componentes. En particular Applet es un contenedor.

Los contenedores más usados son Panel y Window. De hecho los otros contenedores que se usan son extensiones de éstos. Applet es extensión de Panel. Frame y Dialog son extensiones de Window. Por tanto es importante estudiar antes Panel y Window.

Panel es el contenedor más usado. Se utiliza únicamente como apoyo para acomodar componentes. Su aplicación está muy relacionada con el uso de los Despliegues (Layouts) que se estudian en la siguiente sección. Normalmente para crear una interfaz de usuario se utilizan varios paneles cuya única misión es contener componentes u otros paneles que a su vez contienen componentes y paneles.

Un Panel no puede desplegarse solo, tiene que estar contenido en un applet o en una ventana (Window). Las ventanas son los contenedores de la clase Window y estos sí pueden desplegarse solos, aunque en la mayoría de las aplicaciones se utilizan para esto las clases Frame (Marco) y Dialog (Cuadro de diálogo), ambas subclases de Window.

El alumno ya ha visto ejemplos de paneles (los applets son paneles) y de marcos (que son ventanas) en los ejemplos HelloWindows y calcWin de la primera lección. Pero las aplicaciones verdaderamente interesantes de los contenedores dependen de los despliegues, por lo cual se estudiarán ambas cosas simultáneamente en los ejemplos de la siguiente sección.


Despliegues.


Un despliegue es un objeto de la clase Layout. 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 este curso se presentan tres despliegues que son los más fáciles de utilizar: BorderLayout, FlowLayout y GridLayout. Estos tres despliegues pueden combinarse para obtener una gran variedad de interfaces, como puede verse en los ejemplos al final de esta sección.

Estos despliegues tienen dos virtudes importantes: la sencillez y la automatización. Los tres 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.

Nota: Cabe mencionar que la colocación numérica de los componentes también se puede hacer en Java si se aplica el Layout null (setLayout(null)) y la posición y dimensiones de cada componente se determinan 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 de la ventana, pero en muchas ocasiones es útil y además cuando el programador quiere controlarlo todo no hay mejor opción.

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 preDibuja.java al final de la sección).

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 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.

Estos dos despliegues 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 un 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 a la izquierda, centrados o a la derecha, según se pase como parámetro una de las constantes: FlowLayout.LEFT, FlowLayout.CENTER o FlowLayout.RIGHT respectivamente.

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.

Existe otro tipo de despliegue llamado GridBagLayout. Es algo más complicado de utilizar pero ofrece mayor flexibilidad que los otros. 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 lograrlo es necesario especificar algunos parámetros para cada componente que se agrega. Esto se hace utilizando objetos 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

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 hacerle modificaciones para comprender el significado preciso de cada variable de 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:

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.

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. Esto 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 despliegues de Java.

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 lección 5 (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 lección 5.

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


Lección 4, parte b

Índice

Ejercicios de la Lección 04.


José Luis Abreu y Marta Oliveró