Conocer Java AWTprogramacion II
Conocer Java AWTprogramacion II
1.- Introducción
2.- Ventanas: la clase Frame
3.- Componentes Básicos
4.- Eventos de teclado y de ratón
5.- Estilos
6.- Diálogos y mensajes
1.- Introducción
Una de las razones del éxito de Java es la posibilidad desde las primeras versiones, de
una gran cantidad de paquetes de clases destinadas al diseño de interfaces gráficas. En
otros lenguajes (C, C++, etc.), las librerías de componentes gráficos dependían del
fabricante del compilador particular que se decidiera utilizar. Esto favorecía la aparición
de dialectos del lenguaje y la falta de uniformidad en el modelo propuesto.
La variedad de clases gráficas y sus inmensas posibilidades de diseño hacer que un buen
programador en Java no sea sólo aquel que conoce los aspectos básicos del lenguaje y
su filosofía; es necesario también un conocimiento detallado de las clases del API
(application program interface) de Java y sus posibilidades.
Se pueden distinguir, principalmente, 2 grupos de clases destinadas al diseño de
interfaces gráficos en Java:
AWT
Swing
La primera (Abstract Window Toolkit) es la que vamos a estudiar en este curso. El
conjunto de clases Swing nació a partir de AWT, simplificando los aspectos más
engorrosos de AWT, dando mayor flexibilidad al programador para diseñar sus propios
componentes gráficos (gracias all uso de beans) e incorporando numerosos
componentes nuevos.
La pregunta que surge al leer esto es:
Si Swing es más sencillo, más flexible y más potente que AWT,
¿por qué no limitarse a estudiar las clases de Swing?
La razón principal es que, a pesar de ser Swing más fácil de manejar está basado en
conceptos más complejos, difíciles de entender si primero no se conoce AWT; Swing
contiene demasiado de AWT como para, simplemente, ignorarlo. La mayoría de los
autores piensa que es mejor seguir al estudiar el lenguaje la evolución que han seguido
sus diseñadores. Por eso nos limitaremos aquí al estudio de AWT. Si se comprenden los
conceptos de este tema pasar posteriormente a Swing no supondrá ningún problema.
Otro buena razón es que al ser AWT más antiguo, los applets de internet escritos en
AWT funcionan en muchos más exploradores que los escritos con Swing. Por tanto
usando AWT nos aseguramos una mayor compatibilidad.
Las idea clave de esta forma de proceder es la llamada delegación de eventos. En una
aplicación gráfica La función main se encargará de crear la ventana principal, donde se
dispondrán los componentes y se indicará a cada componente a qué clase debe avisar
cuando le suceda un evento. A partir de este momento será el propio lenguaje el que se
encargará de avisar a las clases adecuadas de la existencia de un evento como respuesta
a las acciones del usuario. Esto significa que se pierde el concepto de ejecución
secuencial que hemos visto en los programas con entrada/salida de texto.
La clase Component es una clase abstracta de la que derivan todos los componentes
visuales AWT. Tiene más de 100 métodos de los que vamos a mencionar sólo los más
habituales:
Clase Component
Método Descripción
String getName() Devuelve el nombre del componente
void setName(String) Para fijar el nombre del componente
Dimension1 getSize() Devuelve el tamaño del componente
void setSize(int ancho, int
Para modificar el tamaño del componente
alto)
void setSize(Dimension) Análogo al anterior
Color getBackground Devuelve el color de fondo del componente
void setBackground(Color) Fija el color de fondo del componente
Color getForeground Devuelve el color de primer plano del componente
void setForeground(Color) Fija el color de primer plano del componente
Font2 getFont() Devuelve el tipo de letra asociado al componente
void setFont(Font) Fija el tipo de letra del componente
Boolean getVisible() Indica si el componente es visible
void setVisible(Boolean) Muestra/oculta el componente (útil para ventanas)
Boolean getEnabled() Indica si el componente está activo
Activa/desactiva el componente (útil para botones y
void setEnabled(Boolean)
opciones de menú)
Devuelve el objeto tipo Graphics que puede dibujar en el
Graphics getGraphics()
componente
Llamaremos a este método para pedirle al componente
repaint()
que se redibuje
repaint(int x, int y, int Llamaremos a este método para pedirle al componente
width, int height) que redibuje el rectángulo indicado
Redefiniremos este método (usando herencia) cuando
void Paint(Graphics g)
queramos dibujar algo en el componente
Método que por defecto borra el componente y llama a
void Update(Graphics g) paint() cuando hay que repintar un componente. Se utiliza
sobre todo en animaciones
Indica la posición de la esquina superior izquierda del
Point3 getLocation()
componente en su contenedor
void setLocation(int x, int
Mueve el componente a la posición indicada
y)
void setLocation(Point p) Mueve el componente a la posición indicada
Container getParent() Indica a qué contenedor pertenece el componente
Contenedore
s
Clase Descripción
Panel Contenedor básico que necesita formar parte de una ventana (o página)
Applet Panel preparado para formar parte de una página HTML
Window Una ventana sin título ni casillas para minimizar,cerrar,etc.
Frame Una ventana normal, con título
Ventana que se muestra sobre la ventana actual (Ej.: la típica ventana
Dialog para preguntar "¿Está seguro de ...." y dos botones de Aceptar y
Cancelar)
Similar al anterior, pero especializado para la selección de ficheros (se
FileDialog
suele utilizar en las opciones de "Abrir" o "Grabar como" )
La clase Frame representa en AWT una ventana tal y como estamos acostumbrados a
verlas en un entorno gráfico. Dado que el resto de los componentes formarán parte de
una ventana, parece lógico que comencemos por ella.
Para crear e inicializar una ventana AWT (Frame) vamos a seguir los siguientes pasos:
hará que los componentes se sitúen uno al lado del otro, de izquierda a derecha y de
arriba a abajo.
Observación: Todos los estilos (como FlowLayout) son subclases de la clase Layout
y por eso pueden ser utilizados como argumentos del método setLayout. Es un ejemplo
de polimorfismo.
Observación: Otro ejemplo de polimorfismo: etiq es de tipo Label, pero Label hereda
de Component y por eso etiq puede ser argumento del método add, cuyo argumento está
declarado de tipo Component.
Aviso: Es importante que no olvidemos incorporar los componentes básicos a un
contenedor; en otro caso no podrán ser visibles.
Mostrar la ventana
Esto se hace con el método setVisible heredado de Component.
ventana.setVisible(true);
Aviso: Un error habitual es olvidar este paso con lo que la ventana no se mostrará
WINDOW_OPENED
WINDOW_CLOSING
WINDOW_CLOSED
WINDOW_ICONIFIED
WINDOW_DEICONIFIED
WINDOW_ACTIVATED
WINDOW_DEACTIVATED
WINDOW_GAINED_FOCUS
WINDOW_LOST_FOCUS
WINDOW_STATE_CHANGED
Escribir una clase para atenderlos. Esta clase debe heredar de WindowAdapter o bien
implementar el interfaz WindowListener
void windowActivated(WindowEvent e)
void windowClosed(WindowEvent e)
void windowClosing(WindowEvent e)
void windowDeactivated(WindowEvent e)
void windowDeiconified(WindowEvent e)
void windowIconified(WindowEvent e)
void windowOpened(WindowEvent e)
De todos ellos el que nos interesa ahora es windowClosing que se utiliza cuando el
usuario trata de cerrar la ventana. Para que al pulsar se cierre realmente tendremos que
incluir una llamada a System.exit(0), que fuerza el fin de la aplicación. La clase puede
ser por ejemplo:
class ParaAcabar extends WindowAdapter {
2.3 Ejemplo
Principal.java
import java.awt.*;
import java.awt.event.*;
// estilo
FlowLayout estilo = new FlowLayout();
ventana.setLayout(estilo);
// componentes
Label etiq = new Label("Te estoy mirando...");
ventana.add(etiq);
Observación: En cada fichero .java puede haber una única clase pública, pero
también se permite incluir otras clases -no públicas- que sirvan de clases auxiliares de la
clase pública.
Es muy normal separar el código asociado a la ventana del main, haciendo una clase
aparte que se encargue de la gestión de la ventana. Entonces la aplicación queda
compuesta de dos clases: la clase Ventana, y la clase Principal que se limita a crear la
ventana y a hacerla visible. La configuración de la ventana (colores, tamaño, posición,
componentes, escuchas, etc.) se hará entonces en la constructora de la clase Ventana,
que se definirá hija de la clase Frame:
Ventana.java
import java.awt.*;
import java.awt.event.*;
public Ventana() {
// ventana cuadrada centrada en la pantalla y
// ocupando un tercio de la pantalla
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
// calculamos el tamaño de la ventana a partir del ancho de la
pantalla
int ancho=d.width/3;
int alto=d.height/3;
setSize(ancho, alto);
setLocation(d.width/2-ancho/2,d.height/2-alto/2);
// estilo
FlowLayout estilo = new FlowLayout();
setLayout(estilo);
// componentes
Label etiq = new Label("Te estoy mirando...");
add(etiq);
Principal.java
Constructoras
Tiene 3 constructoras:
Métodos
Aparte de los métodos heredados de Object y Component, esta clase tiene dos métodos
importantes:
Este componente es básico; sobre el suelen recaer las acciones del usuario y a menudo
en sus escuchas asociadas se realiza la parte más complicada del programa. La filosofía
que se sigue es válida para otros componentes que no discutimos aquí, como los menús.
Constructoras
Tiene 2 constructoras:
Button(): Botón con un mensaje vacío.
Button(String etiq): Etiq es el String a mostrar como mensaje.
Métodos
Algunos de los métodos más importantes, además de los heredados de Component, son:
Vamos a ver un primer ejemplo. En este ejemplo se separa la aplicación en dos clases
independientes: la clase con el main y la clase con la ventana:
Ventana.java
package ventanas;
import java.awt.*;
import java.awt.event.*;
// constructora
public Ventana() {
// titulo, estilo, tamaño y posición iniciales
setTitle("Ejemplo de ventana con boton (v.1) ");
setLayout(new FlowLayout());
setSize(300, 100); setLocation(100,50);
// le damos un poco de color a la ventana
setBackground(Color.yellow);
// una etiqueta
etiq = new Label("Un botón:");
add(etiq);
// creamos el botón
botón = new Button("Púlsame");
botón.setBackground(Color.blue);
botón.setForeground(Color.white);
// lo incorporamos a la ventana
// importante: si no se hace esto no sera visible
add(botón);
En este ejemplo aparece la ventana pero al pulsar el botón todavía no hace nada. En el
siguiente apartado veremos como hacer que el botón "reaccione" cuando es pulsado.
Eventos
La idea es que no será el propio botón sino un objeto escucha el que será informado por
Java para que actúe cuando el botón sea pulsado. Para lograr esto hay que:
String getActionCommand() .
Object getSource(): Fuente del evento (objeto de tipo Button).
El siguiente ejemplo hace que el botón, al ser pulsado escriba por pantalla el mensaje
"Gracias".
Ventana.java
package ventanas;
import java.awt.*;
import java.awt.event.*;
// constructora
public Ventana() {
// creamos el botón
botón = new Button("Púlsame");
botón.setBackground(Color.blue);
botón.setForeground(Color.white);
// lo incorporamos a la ventana
// importante: si no se hace esto no sera visible
add(botón);
}
}
Ejercicio: Hacer que el botón escriba al hacer click el número de veces que ha sido
pulsado desde que ha comenzado la aplicación (solución en el siguiente apartado).
Interacción con otros componentes gráficos
Supongamos que pretendemos que el botón cambie de color de fondo cada vez que se le
pulse. Para ello podemos utilizar el método setBackground y generar un color aleatorio
utilizando el método Math.random(). Un primer intento consiste en modificar la clase
Escucha de la siguiente forma:
// escucha del boton
class Escucha implements ActionListener {
public void actionPerformed(ActionEvent e) {
// generamos un color aleatorio
Color c = new
Color((int)(Math.random()*256),(int)(Math.random()*256),
(int)(Math.random()*256));
// cambiamos el color del boton
boton.setBackground(c);
}
}
Pero al compilar el código anterior obtenemos un error:
C:\JCreator LE\MyProjects\gracias\ventanas\Ventana.java:67: cannot
resolve symbol
symbol : variable boton
location: class ventanas.Escucha
boton.setBackground(c);
^
Esta solución no se puede aplicar si queremos interactuar con otro componente distinto
del botón.
Ejemplo: Supongamos que queremos que al pulsar el botón se muestre en la etiqueta el
número de veces que se ha pulsado el botón desde que comenzó la aplicación.
En este caso no nos vale de nada la variable ActionEvent e; la etiqueta está definida en
la clase ventana y debemos ''obtenerla'' de otra forma. Vamos a ver dos posibilidades:
1.
2.
En nuestro caso:
3. Ventana.java
4.
5. package ventanas;
6.
7. import java.awt.*;
8.
9. import java.awt.*;
10. import java.awt.event.*;
11.
12. public class Ventana extends Frame {
13.
14. // constructora
15. public Ventana() {
16.
17. // titulo, estilo, tamaño y posición iniciales
18. setTitle("Ejemplo de ventana con boton (v.3)
");
19. setLayout(new FlowLayout());
20. setSize(300, 100);
21. setLocation(100,50);
22.
23. // le damos un poco de color a la ventana
24. setBackground(Color.yellow);
25.
26. // una etiqueta
27. Label etiq = new Label("Aún no has pulsado");
28. add(etiq);
29.
30. // creamos el boton
31. Button boton = new Button("Púlsame");
32. boton.setBackground(Color.blue);
33. boton.setForeground(Color.white);
34.
35. // incorporamos el boton al frame
36. // importante: si no se hace esto no sera
visible
37. add(boton);
38.
39. // preparamos la escucha del boton
40. Escucha e = new Escucha(etiq);
41. // la registramos
42. boton.addActionListener(e);
43.
44.
45. // añadimos el "listener" para cerrar la
ventana
46. addWindowListener(new ParaAcabar());
47.
48. // la mostramos
49. setVisible(true);
50.
51. }
52. }
53.
54.
55. // clase para cerrar la ventana
56. class ParaAcabar extends WindowAdapter {
57. public void windowClosing(WindowEvent e) {
58. System.exit(0);
59. }
60. }
61.
62.
63. // escucha del boton
64. class Escucha implements ActionListener {
65. int i; // para contar las veces que se ha pulsado
66. Label etiqueta; // etiqueta que se modificará
67.
68.
69. public Escucha(Label etiqueta) {
70. this.etiqueta = etiqueta;
71. i=0;
72. }
73.
74. public void actionPerformed(ActionEvent e) {
75. i++;
76. etiqueta.setText("Has pulsado "+i+" veces");
77. }
78. }
79.
80. Ahora sí que el programa funcionará correctamente:
81.
82.
83.
84.
Java permite escribir una clase auxiliar dentro de la clase con la que
''colabora''. Así podemos definir la clase escucha como una subclase
privada de la clase Ventana, que al ser miembro de la clase tiene acceso a
los atributos:
85. package ventanas;
86.
87. import java.awt.*;
88.
89. import java.awt.*;
90. import java.awt.event.*;
91.
92. public class Ventana extends Frame {
93. private int contador;
94. private Label etiq;
95. private Button botón;
96.
97. // constructora
98. public Ventana() {
99. contador = 0;
100.
101. // titulo, estilo, tamaño y posición iniciales
102. setTitle("Ejemplo de ventana con boton (v.3)
");
103. setLayout(new FlowLayout());
104. setSize(300, 100); setLocation(100,50);
105.
106. // le damos un poco de color a la ventana
107. setBackground(Color.yellow);
108.
109. // una etiqueta
110. etiq = new Label("Aún no has pulsado");
111. add(etiq);
112.
113. // creamos el boton
114. botón = new Button("Púlsame");
115. botón.setBackground(Color.blue);
116. botón.setForeground(Color.white);
117.
118. // incorporamos el boton al frame
119. // importante: si no se hace esto no sera
visible
120. add(botón);
121.
122. // preparamos la escucha del boton
123. Escucha e = new Escucha();
124. // la registramos
125. botón.addActionListener(e);
126.
127. // añadimos el "listener" para cerrar la
ventana
128. addWindowListener(new ParaAcabar());
129. }
130.
131. // escucha del botón
132. private class Escucha implements ActionListener {
133. public void actionPerformed(ActionEvent e) {
134. contador++;
135. etiq.setText("Has pulsado "+contador+" veces");
136. }
137. }
138. } // fin de la clase Ventana
139.
140. // clase para cerrar la ventana
141. class ParaAcabar extends WindowAdapter {
142. public void windowClosing(WindowEvent e)
{System.exit(0);}
143. }
Esta solución es más sencilla; nos ahorramos la constructora, la copia de la referencia
para acceder a los objetos, etc. A cambio es menos elegante y más limitada; por ejemplo
no nos permite definir la clase escucha en un fichero aparte, para poder compartirla por
varias aplicaciones.
Utilizando la misma escucha para varios botones
Supongamos que queremos tener una etiqueta que haga de contador comenzando en 0.
Incluiremos dos botones, uno para incrementar el contador y otro para decrementarlo. A
la hora de establecer las escuchas hay dos posibilidades:
1. Escribir dos clases escucha, una para el botón de incrementar y otra para
el de decrementar.
2. Utilizar la misma escucha para ambos.
El segundo método es, en este caso, más cómodo, pero tenemos que ser capaces de
distinguir dentro del método actionPerformed cuál de los dos botones ha sido pulsado,
para así incrementar o decrementar el contador. Para esto podemos utilizar el método
setActionCommand de la clase Button y getActionCommand de ActionEvent, tal y como
muestra el programa siguiente:
Ventana.java
package ventanas;
import java.awt.*;
import java.awt.*;
import java.awt.event.*;
public class Ventana extends Frame {
// constructora
public Ventana() {
// las etiquetas
Font fuente = new Font("Arial", Font.PLAIN, 20);
Label etiq = new Label("Contador: ");
etiq.setFont(fuente);
add(etiq);
Constructoras
Para TextField:
Métodos
La clase TextField coincide con las clases anteriores en la definición de los métodos
setText(String cadena) y String getText(). Algunos otros métodos de interés:
Eventos
En cuanto a los eventos, la diferencia principal con la clase Button es que el método
ActionEvent de la clase escucha se utiliza cuando se pulsa Enter. También se puede
controlar cual es la tecla pulsada, como veremos al hablar de los eventos de teclado,
pero estos eventos no son específicos de la clase TextField sino comunes a todos los
Component.
Ejemplo: Clase para representar una ventana de entrada a un sistema, con login y
password:
PalabraClave.java
package claves;
import java.awt.*;
import java.awt.event.*;
public PalabraClave() {
// ventana centrada
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
int ancho=300, alto=200;
setSize(ancho, alto);
setLocation(d.width/2-ancho/2,d.height/2-alto/2);
// tipo de letra
Font fuente = new Font("Arial", Font.PLAIN, 18);
setFont(fuente);
// un poco de color
setBackground(Color.cyan);
if (válidos(login.getText(), pass.getText()))
etiq3.setText("Datos válidos");
else
etiq3.setText("Datos no válidos");
} // Ventana
Métodos y Eventos
Los métodos y eventos son como los de TextField con algunos métodos añadidos, entre
los que podemos destacar:
void replaceRange(String str, int start, int end) : Cambia el texto entre
las posiciones start y end por el texto str.
insert(String str, int pos): Inserta el texto en la posición indicada.
append(String str): Añade el texto indicado al final.
La clase Checkbox nos permite mostrar texto acompañado de casillas con dos estados:
marcada o no marcada. Varios Checkbox pueden agruparse de forma que nos
aseguremos de que sólo una casilla está marcada en cada momento. Vamos a ver las dos
posibilidades en dos ejemplos separados: Casillas no agrupadas
En este caso basta con declarar y añadir los Checkbox independientemente. La etiqueta
asociada a la casilla se puede fijar en la constructora o bien posteriormente con el
método setLabel(String). El estado (activada o no) se puede modificar y consultar con
los métodos setState(boolean) y getState(), respectivamente. El siguiente ejemplo
muestra el uso de este componente:
Ventana.java
import java.awt.*;
import java.awt.event.*;
public Ventana() {
// objeto de tipo ventana
setTitle("Prueba de Checkbox");
setSize(380, 150);
setLayout(new FlowLayout());
Font fuenteNegrita = new Font("Arial",Font.BOLD,16);
setFont(fuenteNegrita) ;
// otra forma
casilla2 = new Checkbox("Lectura");
casilla3 = new Checkbox("Viajes");
casilla4 = new Checkbox("Cine");
// hacemos que la casilla Cine aparezca marcada
casilla4.setState(true);
//////////////////////////////////////////////////////
// escucha del boton
class EscuchaBotón implements ActionListener {
public void actionPerformed(ActionEvent e) {
String aficiones = "Ha elegido: ";
if (casilla1.getState()) aficiones += casilla1.getLabel()+"
";
if (casilla2.getState()) aficiones += casilla2.getLabel()+"
";
if (casilla3.getState()) aficiones += casilla3.getLabel()+"
";
if (casilla4.getState()) aficiones += casilla4.getLabel()+"
";
Casillas agrupadas
Similar al anterior, pero agrupando las casillas por medio de un objeto tipo
CheckboxGroup, para lo que se usa una tercera constructora que permite indicar el
grupo al que pertenece la casilla, así como si está activa (cada grupo tendrá como
máximo una casilla marcada). Los métodos de CheckboxGroup Checkbox
getSelectedCheckbox() y void setSelectedCheckbox(Checkbox) sirven para obtener y
cambiar, respectivamente, el Checkbox seleccionado. Ejemplo:
Ventana.java
import java.awt.*;
import java.awt.event.*;
public Ventana() {
setTitle("Prueba de CheckboxGroup");
setSize(300, 80);
setBackground(Color.yellow);
setLayout(new FlowLayout());
Font fuenteNegrita = new Font("Arial",Font.BOLD,16);
setFont(fuenteNegrita) ;
Por su parte, el parámetro de tipo KeyEvent contiene los siguientes métodos que nos
ayudan a identificar la tecla concreta:
Ejemplo: Hacer que la posición de una etiqueta cambie con las teclas de cursor. El
programa también avisará si se pulsa la tecla Bloq. Núm.
Teclas.java
import java.awt.*;
import java.awt.event.*;
public Teclas() {
// titulo, estilo, tamaño y posición iniciales
setTitle("Teclas");
setLayout(new FlowLayout());
// ventana centrada
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
int ancho=300, alto=200;
setSize(ancho, alto);
setLocation(d.width/2-ancho/2,d.height/2-alto/2);
// tipo de letra
Font fuente = new Font("Arial", Font.PLAIN, 18);
setFont(fuente);
// un poco de color
setBackground(Color.cyan);
// escucha de teclaro
class EscuchaTeclas implements KeyListener {
private Label etiq;
Existen dos interfaces para el control del ratón, cada uno correspondiendo a un tipo de
evento.
MouseListener
Sirve para detectar las pulsaciones del ratón y responde a los eventos del tipo
MouseEvent. El interfaz consta de 5 métodos:
Ejemplo: Vamos a mover un botón para que el usuario no pueda pulsarlo nunca:
CorreRaton.java
import java.awt.*;
import java.awt.event.*;
public class CorreRaton extends Frame {
public CorreRaton() {
// titulo, estilo, tamaño y posición iniciales
setTitle("Botón tímido");
setLayout(new FlowLayout());
setBackground(Color.cyan);
// ventana centrada
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
int ancho=300, alto=150;
setSize(ancho, alto);
setLocation(d.width/2-ancho/2,d.height/2-alto/2);
// la mostramos
setVisible(true);
botón.setLocation(p);
}
MouseMotionListener
Detecta los movimientos del ratón, y también cuando el ratón se arrastra pulsado (para
marcar zonas). Este interfaz tiene dos métodos:
5.- Estilos
5.1 Introducción
5.2 Estilo FlowLayout
5.3 Estilo BorderLayout
5.4 Estilo GridLayout
5.5 Paneles
5.1 Introducción
Observación: Aunque cada contenedor tiene un único estilo, podemos mezclar estilos
incorporando contenedores dentro de contenedores. La clase Panel está pensada con
este propósito.
Igual que en los puntos anteriores, aquí no vamos a ver todos los estilos de los que
dispone Java (¡hay 21 estilos diferentes!), contentándonos con ver algunos de los más
comunes y esperando que sea suficiente para captar la "filosofía" y que a partir de éstos
comprender el resto sea más sencillo.
EstiloFlowLayout.java
import java.awt.*;
import java.awt.event.*;
public EstiloFlowLayout() {
// titulo, estilo, tamaño y posición iniciales
setTitle("FlowLayout");
setBackground(Color.cyan);
setSize(300,200);
El resultado es:
5.3 Estilo BorderLayout
Ejemplo
Ventana.java
import java.awt.*;
import java.awt.event.*;
public Ventana() {
// titulo, estilo, tamaño y posición iniciales
setTitle("BorderLayout");
setBackground(Color.cyan);
setSize(300,200);
// creamos 5 botones
Button este = new Button("Este");
este.setBackground(Color.blue);
Button oeste = new Button("Oeste");
oeste.setBackground(Color.red);
Ejemplo
Grid.java
import java.awt.*;
import java.awt.event.*;
public Grid() {
// titulo, estilo, tamaño y posición iniciales
setTitle("GridLayout");
setBackground(Color.yellow);
setSize(250,150);
La clase Panel representa un contenedor que no puede existir por su cuenta, sólo
insertado en otro contenedor (como por ejemplo en un Frame(). Su estilo por defecto es
FlowLayout, aunque como en todos los contenedores se puede modificar con setLayout.
Se utiliza a menudo para combinar diferentes estilos en una misma ventana.
Ejemplo: Vamos a escribir el aspecto previo que tendría una aplicación para jugar al
ajedrez; incluyendo el tablero vacío, un título inicial y botones para comenzar y salir. El
resultado debe ser:
Tablero.java
import java.awt.*;
import java.awt.event.*;
// ventana centrada
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
int ancho=300, alto=350;
setSize(ancho, alto);
setLocation(d.width/2-ancho/2,d.height/2-alto/2);
// ponemos la etiqueta
Font fuente = new Font("Arial", Font.BOLD, 20);
Label etiq = new Label("A J E D R E Z ", Label.CENTER);
etiq.setFont(fuente);
etiq.setForeground(new Color(100,0,50));
add(etiq, BorderLayout.NORTH);
// lo ponemos en el centro
add(tablero,BorderLayout.CENTER);
botones.add(empezar);
botones.add(acabar);
add(botones, BorderLayout.SOUTH);
6.- Dibujando
6.1 Introducción
6.2 La clase Canvas
6.3 La clase Graphics
6.4 Mostrando imágenes
6.5 Un poco de animación
6.1 Introducción
¿Cómo dibujar?
Para dibujar en Java hay que conocer inicialmente los siguiente conceptos.
De todo esto se deduce que para dibujar podemos "pedirle prestado" su objeto
Graphics() al componente en el que queramos dibujar. Ejemplo: Botón subrayado
(primera versión).
Ventana.java
import java.awt.*;
import java.awt.event.*;
// ventana centrada
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
int ancho=200, alto=90;
setSize(ancho, alto);
setLocation(d.width/2-ancho/2,d.height/2-alto/2);
// la mostramos
setVisible(true);
}
}
El resultado es:
El problema está en que cada vez que se repinta el botón no se vuelve a pintar la línea.
De hecho el dibujo sólo se hace una vez, al estar en la constructora, y cada vez que hay
que pintar el botón.
El método paint
Para arreglar este problema hay que saber algunas cosas más.
Así pues, la solución está en sobreescribir el método paint() del componente en el que
queremos dibujar; y para ello deberemos hacer una nueva clase que herede de la clase
de dicho componente, tal y como muestra el siguiente ejemplo: Ejemplo: Botón
subrayado (segunda versión).
BotonSubrayado.java
import java.awt.*;
Ventana.java
import java.awt.*;
import java.awt.event.*;
// ventana centrada
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
int ancho=200, alto=90;
setSize(ancho, alto);
setLocation(d.width/2-ancho/2,d.height/2-alto/2);
// la mostramos
setVisible(true);
Graphics g = botón.getGraphics();
g.setColor(Color.green);
g.fill3DRect(5,40,70,10,true);
g.fill3DRect(80,40,90,10,true);
}
}
Aunque hemos visto que se puede dibujar en cualquier componente, lo normal es querer
dibujar sólo en un espacio en blanco destinado a tal fin. Con este propósito se incluye en
java el componente Canvas. El procedimiento para incluir gráficos como parte de una
ventana es:
1. Declarar una clase que herede de canvas.
2. Sobrescribir el método void paint(Graphics g) (y/o void update(Graphics g)) de
la nueva clase de forma que se dibuje el gráfico deseado.
3. Añadir un objeto de la clase nueva como componente de la ventana.
Una aplicación hecha siguiendo esta idea tendrá al menos tres clases, con la siguiente
estructura:
Lienzo.java
import java.awt.*;
Ventana.java
import java.awt.*;
import java.awt.event.*;
public Ventana() {
....
....
Lienzo l = new Lienzo();
add(l);
.......
......
}
}
......
Principal.java
De esta clase no nos interesan sus constructoras, porque nunca vamos a construir un
objeto Graphics; sólo vamos a utilizar un objeto ya existente.
Métodos Principales
abstract void clearRect(int x, int y, int width, int height)
Borra el rectángulo especificado por sus parámetros; es
decir lo pinta del color de fondo.
abstract void copyArea(int x, int y, int width, int height,
int dx, int dy)
Copia el área del componente especificada por los
parámetros a una distancia dx and dy. Si se quiere que se
copie a la izquierda habrá que dar un valor dx negativo.
Análogamente, para copiar más arriba de la posición actual
habrá que indicar un valor dy negativo.
void draw3DRect(int x, int y, int width, int height,
boolean raised)
Dibuja un rectángulo al que se da aspecto de 3d, bien
mostrándolo ligeramente elevado (si raised es true) o
hundido (raised false)
abstract void drawArc(int x, int y, int width, int height,
int startAngle, int arcAngle)
Dibuja un arco (circular o elíptico), empezando en el
ángulo startAngle y finalizando en arcAngle. El arco
estará inscrito en el rectángulo indicado por los parámetros,
con centro en el centro de dicho rectángulo.
Ejemplo: El siguiente arco está escrito con la instrucción
g.drawArc(50,50,150,100,0,260);. También se
muestra en el dibujo el rectángulo (dibujado con
g.drawRect(50,50,150,100);).
Para mostrar imágenes que están en disco en forma .gif o .jpg podemos seguir el
procedimiento siguiente:
Ejemplo: Vamos a mostrar una secuencia de imágenes para producir el efecto de una
animación.
Saluda.java
import java.awt.*;
import javax.swing.*;
public Saluda() {
t = new Image[10];
Ventana.java
import java.awt.*;
import java.awt.event.*;
public Ventana() {
// titulo, estilo, tamaño y posición iniciales
setTitle("saluda a los señores");
// ventana centrada
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
int ancho=200, alto=250;
setSize(ancho, alto);
setLocation(d.width/2-ancho/2,d.height/2-alto/2);
add(boton, BorderLayout.SOUTH);
// la mostramos
setVisible(true);
}
}
Principal.java
Los diálogos son ventanas "hijas" de la ventana principal que se utilizan normalmente
para mostrar información, errores, o pedir confirmación. El ejemplo más habitual es la
ventana con el mensaje "Desea salir de la aplicación?" con los botones de aceptar y
cancelar. Hay dos tipos de diálogos:
Dado que los diálogos son un tipo especial de ventanas, no tenemos que describir sus
métodos, tan sólo sus constructoras:
Constructoras
Donde vent es la ventana madre, msg es el título del cuadro de diálogo y mode debe ser
o bien FileDialog.LOAD si el diálogo se utiliza para abrir un fichero o FileDialog.SAVE
si se utiliza para grabar un fichero.
Métodos
import java.awt.*;
import java.awt.event.*;
public Ventana() {
setTitle("Entrada de datos");
setLayout(new FlowLayout());
setSize(300,100);
setLocation(300,200);
Label etiqInfo = new Label("Fichero seleccionado: ");
Label etiqSel = new Label();
add(etiqInfo);
add(etiqSel);
// la mostramos
setVisible(true);
} // if
}
}
Los diálogos más comunes son los diálogos modales que se utilizan para presentar
información, o bien informar de un error, y que incluyen un botón Aceptar o bien
botones Aceptar y Cancelar. Por eso en swing se incluyo una clase especial para
representar este tipo de diálogos, la clase JOptionPane, que resulta muy útil a la hora de
presentar información debido a su sencillez.
También hay 5 constantes que pueden utilizarse para indicar el tipo de mensaje que se
está mostrando. La selección de la constante adecuada influirá en el icono que se
presentará en la ventana modal:
ERROR_MESSAGE
INFORMATION_MESSAGE
WARNING_MESSAGE
QUESTION_MESSAGE
PLAIN_MESSAGE
Por último, aunque podemos incluir en el diálogo los botones que deseemos, hay 4
constantes que definen los conjuntos de botones más usuales:
DEFAULT_OPTION YES_NO_OPTION YES_NO_CANCEL_OPTION
OK_CANCEL_OPTION
El primero muestra sólo un botón de aceptar (el significado del resto es obvio a partir
del nombre). Vamos a ver algunos ejemplos en el siguiente programa:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*; // para JOptionPane
public Ventana() {
setTitle("Entrada de datos");
setLayout(new FlowLayout());
setSize(200,100);
setLocation(300,200);