Lección 04

Componentes y Diseño de Interfaces, parte b.


Ventanas, marcos y cuadros de diálogo.


La programación gráfica de aplicaciones Java que no son applets, requiere de una clase especial llamada Window y de dos extensiones suyas que se usan con mayor frecuencia que Window: Frame y Dialog, que en español se llaman marco y cuadro de diálogo respectivamente. Los objetos de la clase Window se llaman ventanas.

Pulsando el botón de este applet aparece un marco desde el cual se pueden lanzar: una ventana, un cuadro de diálogo y otro marco.

El alumno debe pulsar el botón "ventanas" y aparecerá un pequeño marco con tres botones: ventana, dialogo y marco, que al pulsarlos harán aparecer un objeto de cada clase.

Podrá observar que la ventana no tiene orilla ni título ni botón de salida, el cuadro de diálogo sí tiene orilla, título y botón de salida, pero no tiene botones de minimizar y maximizar ni un menú. Finalmente el marco tiene todo: orilla, título, botones de minimizar y maximizar y una barra de menú. Estas son precisamente las características que más distinguen entre sí a las ventanas, cuadros de diálogo y marcos.

El marco ofrece más funcionalidad que el cuadro de diálogo y éste más que una ventana. Por este motivo los marcos se utilizan con mayor frecuencia y las ventanas puras sólo de vez en cuando.

Abajo aparecen los contenidos de "ventana.java", "dialogo.java" y "marco.java" que son las clases construídas para crear los objetos del ejemplo. El alumno debe estudiarlos cuidadosamente. El archivo "ventanas,java" responsable de crear el marco que lanza los otros tres, así como el applet que lanza las tres ventanas, se estudiarán como ejemplos de la lección 5. Por ahora el alumno debe prestar particular atención a la creación, configuración y despliegue de la ventana, el cuadro de diálogo y el marco del ejemplo.

El alumno observará los siguientes pasos en la construcción de todas las ventanas (y cuadros de diálogo y marcos):

(Se repite el applet junto a cada texto para que el alumno pueda mirar simultáneamente el código y las ventanas.)

El alumno observará que a pesar de que dialogo tiene botón para destruirlo, éste no funciona. Esto se debe a que lo único que ocurre cuando se pulsa ese botón es que se genera un evento de tipo WindowEvent. Para que el botón funcione es necesario hacer que la ventana "escuche" estos eventos y para ello hay que implementar la interfaz WindowListener que tiene seis métodos abstractos. Esto puede verse en "marco.java" donde sí se programó que el marco se destruyera.

El alumno debe observar que cada marco que se crea aparece en la barra de tareas de Windows95/98. Esto es porque los marcos son auténticas ventanas de Windows95/98. En cambio las ventanas y los cuadros de diálogo son siempre dependientes de un marco. Esto se refleja en que sus constructores de Window y Dialog requieren de un Frame que actúe como padre, mientras que el constructor de Frame no pide nada o tan sólo el título.

En los ejemplos se mantuvo siempre el despliegue por defecto, que es BorderLayout (recuerde que Panel tiene por defecto un despliegue de tipo FlowLayout) y sólo se agregaron tres botones a "ventanas" y una etiqueta a "ventana", a "dialogo" y a "marco", pero no hay que olvidar que las ventanas son contenedores y por lo tanto se pueden utilizar en ellas todos los tipos de despliegues y agregarles todos los contenedores y componentes que se desee.

En "Marco.java" el alumno puede ver cómo se agrega una barra de menú a un marco y cómo se configura un menú. Éste es el tema de la última parte de esta larga lección.


Menús.


Las barras de menús sólo pueden aparecer en un marco (Frame) y cada marco sólo puede tener una barra de menús. Para agregar una barra de menús a un marco basta crearla y asignarla al marco mediante la función setMenuBar. Es decir, basta escribir estas dos líneas:

dentro de la construcción del marco. setMenuBar es un método de Frame.

A una barra de menús se le pueden agregar menús. Para ello hay que construir cada menú dándole un nombre. Por ejemplo:

crea dos menús de nombre "archivo" y "edición" respectivamente. Estos dos menús pueden agregarse a la barra de menús mb de esta manera:

Finalmente, a los menús se les pueden agregar elementos de menú (MenuItem) que se crean también asignándoles un nombre a cada uno. Por ejemplo:

crea tres elementos de menú, los cuales pueden agregarse, por ejemplo, a archivo de esta manera:

Para crear una línea de separación dentro de un menú se agrega un elemento de menú de nombre "-" así;

o simplemente:

pues el método Menu.add(String cadena) crea un elemento de menú con nombre cadena y lo agrega al menú.

La instrucción

haría que la opción "nuevo" apareciera deshabilitada.

A un menú se le puede agregar otro menú así:

y también un CheckboxMenuItem que es una versión del interruptor (Checkbox) especial para incluirse en un menú.

Todas estas operaciones para construir un menú aparecen en el ejemplo siguiente. Al pulsar el botón "menú" aparece un marco con un menú completo para un programa. El alumno debe estudiar cuidadosamente el ejemplo y su código que aparece a continuación.



Gráficas.


Los gráficos en Java se tratan con unas pocas clases del paquete java.awt. La más importante de estas clases es java.awt.Graphics.

Las variables privadas de java.awt.Graphics guardan el color para dibujar, el modo de dibujo (XOR o normal), y la información necesaria sobre el espacio en el que se va a dibujar. Se puede dibujar sobre cualquier componente, es decir, sobre cualquier objeto de tipo java.awt.Component. El método getGraphics() de java.awt.Component devuelve un objeto de tipo Graphic listo para realizar dibujos. Casi siempre se dibuja sobre alguna de las subclases Canvas, Panel o Applet de Component. En esta lección nos limitaremos a utilizar los componentes sin entrar en los detalles de su contrucción y su despliegue.

El siguiente Applet ilustra cómo se utiliza la clase Graphics para dibujar.

Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.
Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.

Como puede apreciarse en el código del Applet, los dibujos se realizan dentro del método public void paint(Graphics g). Este método es invocado por el navegador o el intérprete de Java cada vez que es necesario pintar la superficie asignada al applet. El propio sistema se encarga de pasarle al método un objeto de la clase Graphics que puede utilizarse directamente para realizar los dibujos.

En el ejemplo se utilizan algunos de los métodos de la clase Graphics como drawLine, drawRect y drawOval y también se ilustra cómo se escogen los colores llamando al método setColor al que se le pasan los colores mediante unos objetos constantes de la clase java.awt.Color, que se estudia en la siguiente sección.

Ésta es una lista de los métodos y variables de la clase Graphics que se utilizan para dibujar, con una breve descripción. Todos los métodos devuelven void y son públicos. Los rectángulos se especifican con cuatro variables de tipo int: x,y,width y height que son las coordenadas del punto arriba a la izquierda del rectángulo, su ancho y su alto. Por brevedad en la escritura, utilizaremos los símbolos w y h en lugar de width y depth.

clearRect(int x,int y,int w,int h) Llena el rectángulo con el color de fondo.
(Este método no se recomienda, es mejor utilizar fillRect.)
clipRect(int x,int y,int w,int h) Limita la acción de dibujo al rectángulo.
copyArea(int x,int y,int w,int h,int dx,int dy) Copia el rectángulo al punto (x+dx,y+dy).
draw3DRect(int x,int y,int w,int h,boolean elevado)

Dibuja un rectángulo remarcado.

drawArc(int x,int y,int w,int h,int ai,int af) Dibuja un arco elíptico inscrito en el rectángulo, con ángulo inicial ai y ángulo final af.
drawBytes(byte[] data,int L,int x,int y) Escribe el texto de los primeros L bytes de data, a partir de x,y.
drawChars(char[] data,int L,int x,int y) Escribe el texto de los primeros L chars de data, a partir de x,y.
drawImage(Image img,int x,int y,ImageObserver io) Dibuja la imagen img a partir de x,y. io el objeto que deberá ser notificado cuando la imagen termina de cargarse. Normalmente se utiliza this como ImageObserver
drawImage(Image img,int x,int y,Color bgc, ImageObserver io) Igual que el anterior pero los pixels transparentes se dibujan de color bgc.
drawImage(Image img,int x,int y,int w,int h, ImageObserver io) Dibuja la imagen img a partir de x,y y acomodándola a un ancho w y un alto h. Este método puede ampliar o reducir la imagen.
drawImage(Image img,int x,int y,int w,int h, Color bgc,ImageObserver io) Combina la función de los dos métodos anteriores.
drawLine(int x1,int y1,int x2,int y2) Dibuja una línea recta del punto x1,y1 al punto x2,y2. Este método no utiliza un rectángulo como referencia para el dibujo.
drawOval(int x,int y,int w,int h) Dibuja una elipse contenida en el rectángulo.
drawPolygon(int[] x,int[] y,int N) Dibuja el polígono de N vértices con las coordenadas especificadas.
drawPolygon(Polygon p) Dibuja el polígono p (una clase especial del awt).
drawRect(int x,int y,int w,int h) Dibuja el rectángulo.
drawRoundRect(int x,int y,int w,int h,int aw,int ah) Dibuja un rectángulo con vértices redondeados. aw es el ancho del arco y ah el alto.
drawString(String s,int x,int y) Escribe el texto de la cadena s, a partir de x,y.
fill3DRect(int x,int y,int w,int h,boolean elevado) Rellena rectángulo remarcado.
fillArc(int x,int y,int w,int h,int ai,int af) Rellena un arco elíptico inscrito en el rectángulo, con ángulo inicial ai y ángulo final af.
fillOval(int x,int y,int w,int h) Rellena una elipse contenida en el rectángulo.
fillPolygon(int[] x,int[] y,int N) Rellena el polígono de N vértices con las coordenadas especificadas.
fillPolygon(Polygon p) Rellena el polígono p (una clase especial del awt).
fillRect(int x,int y,int w,int h) Rellena el rectángulo.
fillRoundRect(int x,int y,int w,int h,int aw,int ah) Rellena un rectángulo con vértices redondeados. aw es el ancho del arco y ah el alto.
setColor(Color c) Fija el color para dibujar.
setFont(Font f) Fija la fuente de letras para escribir.
setPaintMode() Fija el estilo normal para dibujar (quita el XOR).
setXORMode(Color c1) Fija el estilo XOR para dibujar. En particular dibuja en color c1 los pixels de color c (el de setColor) y viceversa.

Graphics tiene otros métodos para obtener el color de dibujo y la fuente de letras, que el alumno puede consultar en las referencias, pero éstos son todos los métodos que se utilizan para dibujar.

El siguiente applet muestra dibujos en donde se utilizan casi todos estos métodos. El alumno debe buscar y estudiar el código correspondiente a cada dibujo. Observará que la imagen se prepara antes cargándola con el método getImage.

La siguiente sección explica la estructura y uso de los colores en Java.


Colores.


La clase java.awt.Color se utiliza para representar cualquier color. En primer lugar, hay varios colores predefinidos en la clase Color que son los que aparecen en la siguiente tabla con sus nombres en castellano y sus componentes de rojo, verde y azul en la escala de 0 a 255.

black negro rojo=0, verde=0, azul=0
darkGray gris oscuro rojo=64, verde=64, azul=64
gray gris rojo=128, verde=128, azul=128
lightGray gris claro rojo=192, verde=192, azul=192
white blanco rojo=255, verde=255, azul=255
magenta magenta rojo=255, verde=0, azul=255
blue azul rojo=0, verde=0, azul=255
cyan cian rojo=0, verde=255, azul=255
green verde rojo=0, verde=255, azul=0
yellow amarillo rojo=255, verde=255, azul=0
orange naranja rojo=255, verde=200, azul=0
red rojo rojo=255, verde=0, azul=0
pink rosa rojo=255, verde=175, azul=175

Los demás colores se crean usando alguno de los constructores de la clase Color:

c=new Color(int rojo,int verde,int azul)

crea un color c con las cantidades indicadas de rojo, verde y azul cuyos valores deben estar entre 0 y 255. Igualmente

c=new Color(double r,double v,double a)

crea un color con r,v y a partes de rojo, verde y azul respectivamente, sólo que en este caso r, v y a deben ser números entre 0.0 y 1.0. Finalmente:

c=new Color(int i)

también crea un color y también lo hace especificando sus partes de rojo, verde y azul, sólo que lo hace implícitamente. Supongamos que la representación hexadecimal de i es por ejemplo 0xffc08040. Entonces el color creado tiene 0xc0=192 de rojo, 0x80=128 de verde y 0x40=64 de azul. Los ocho bits más altos no contribuyen al color, sin embargo, una imagen suele representarse con un int para cada pixel y el color del pixel coincide con el que se crearía de esta manera, pero además si los bits más altos no están encendidos, es decir si no comienza con 0xff, entonces el pixel resulta parcial o totalmente transparente.

El siguiente applet muestra al centro el color que se obtiene con cada combinación de rojo, verde y azul en la escala de 0 a 255. Las barras de desplazamiento permiten elegir cualquier combinación deseada.


Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.
Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.

El alumno puede usar las barras de desplazamiento para igualar los colores predefinidos (compare su resultado con los valores de la tabla). Conviene que el alumno observe el código del applet y se vaya familiarizando con la construcción, configuración y despliegue de los componentes y con el tratamiento de eventos, que se estudiarán en las próximas lecciones. Presentamos otra versión más sencilla de este applet pero que recibe su color inicial como parámetros en expresión hexadecimal y también tiene un método público String getColor() que devuelve el color en expresión hexadecimal.

 

Aquí vería un applet si su navegador reconociese la etiqueta de APPLET. Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.

Este applet se usará en la sección de JavaScript, para definir colores en otro applet.

La siguiente sección explica cómo se utilizan las fuentes de letras.


Letras.


Las fuentes de letras se representan con objetos de la clase java.awt.Font que tiene un solo constructor:

Font f=new Font(String nombre,int estilo,int tamaño)

En este constructor todos los parámetros tienen un conjunto limitado de posiblidades. El nombre tiene que ser uno de los que aparecen en la siguiente tabla, donde también aparecen los nombres de las fuentes equivalentes de Windows.

"Helvetica" "Arial"
"TimesRoman" "Times New Roman"
"Courier" "Courier New"
"Dialog" "MS Sans Serif"
"DialogInput" "MS Sans Serif"
"ZapfDingbats" "WingDings"

Es necesario usar los nombre a la izquierda de la tabla, que son los propios de Java.

Hay sólo cuatro estilos que se obtienen usando tres constantes de la clase Font, como se muestra en la tabla.

Font.PLAIN estilo
Font.BOLD estilo
Font.ITALIC estilo
Font.BOLD+Font.ITALIC estilo

Finalmente, el tamaño debe ser un entero mayor que 6. El tamaño se mide en "puntos". Estos "puntos" representan el tamaño vertical de las letras a razón de poco más de un pixel por "punto", aproximadamente. Esto no es exacto porque las fuentes están diseñadas para las impresoras y no para la pantalla. Hay 72 "puntos" en una pulgada o aproximadamente 28 puntos en un centímetro, así que una fuente de 14 puntos medirá medio centímetro de alto cuando se imprime en papel. La representación en la pantalla corresponde a poco más de un pixel por punto, o más precisamente, una fuente de 12 puntos ocupa unos 12 pixels en sentido vertical. El valor exacto se obtiene usando la clase FontMetrics, como se explica más adelante.

En este applet se pueden ver los diferentes tipos de letras, estilos y tamaños. El alumno debe observar el aspecto del texto eligiendo diversas fuentes, estilos y tamaños.


Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.

Aquí está el código del applet:

Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.

Conviene que el alumno memorice los nombres de las fuentes y aprenda a construir la fuente que desee eligiendo los parámetros adecuados para el constructor. Para ello conviene que estudie detenidamente el código del applet. Conviene también que observe la construcción de los componentes y el tratamiento de los eventos, que se estudiarán detenidamente en la lección 5.

Nota: En Java 2 se pueden usar las otras fuentes del sistema, pero sólo en las aplicaciones autónomas, en los applets no se puede pues éstos no tienen acceso al sistema.

Si se desea dibujar texto con precisión es importante conocer la clase java.awt.FontMetrics que es la que nos informa de todas las medidas de una fuente de letras.

El último ejemplo de esta lección ilustra el significado de las diversas variables de la clase FontMetrics. El alumno debe observar los valores de las variables y el aspecto de la palabra escrita eligiendo diversas fuentes, estilos y tamaños.


Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.

Aquí está el código del applet:

Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.

Observe que el objeto FontMetrics que se usa en el ejemplo se obtiene del objeto Graphics al cual se le ha asignado la fuente de letras con la que se va a escribir.

El método drawString(String s,int x,int y) comienza a dibujar la cadena usando y como altura para la línea base. El ascenso es el número de pixels que una letra (del alfabeto alfanumérico básico) puede llegar a subir sobre la línea base y el descenso (Descent) es lo que puede llegar a bajar. "Leading" es el número de pixels que se recomienda agregar, además del descenso y el ascenso, para llegar a la línea base del siguiente renglón. Gráficamente aparece representado por la distancia entre la línea superior y la segunda que corresponde al ascenso. La fuente "Courier" tiene Leading nulo. El alumno podrá observar que la altura (Height) es (casi siempre) igual al ascenso más el descenso más el "Leading". También observará que la altura (Height) es siempre un poco mayor que el "tamaño" de la fuente.

El método getMaxAdvance() devuelve el máximo avance (en la dirección horizontal) con una sola letra.

El método stringWidth(String s) devuelve la longitud, en pixels, de la cadena s en la fuente que dio lugar al objeto FontMetrics.

Los métodos getMaxDescent y getMaxAscent devuelven el ascenso y descenso máximos, que quiere decir, incluyendo el alfabeto completo con letras acentuadas y otros caracteres. Casi siempre el ascenso máximo coincide con el ascenso y el descenso máximo coincide con el descenso.

La siguiente sección explica cómo se utilizan los cursores.


Cursores.


Aunque en el JDK 1.0 sólo se podía cambiar el cursor en las ventanas, a partir del JDK 1.1  es posible asignar cualquiera de los 13 cursores predeterminados a cada Component. A partir de Java 2 es posible crear cursores nuevos. En esta sección sólo explicaremos cómo utilizar los cursores predeterminados, lo cual es muy sencillo. Para muestra basta un botón... bueno, en este caso hemos hecho un applet con 13 botones. Los botones tienen los nombres de sus respectivos cursores. Basta que el lector pase cursor del ratón sobre el botón para que éste cambie al asignado a ese botón.

Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.

Abajo aparece el código Java del applet de arriba. Como el lector podrá comprobar, para asignar un cursor a un componete bastan dos pasos:

1) Crear un cursor del tipo deseado con la instrucción Cursor cur= new Cursor(int cursorIndex);
2) Asignar el nuevo cursor al Component comp mediante la instrucción comp.setCursor(cur);

Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.

El método getCursor() de Component devuelve el número del cursor asignado a la componente. Por defecto todos los componentes tienen asignado el DEFAULT_CURSOR.


Lección 4, parte a

Índice

Ejercicios de la Lección 04.


José Luis Abreu y Marta Oliveró