Tema 5: Desarrollo de aplicaciones gráficas
1.- Introducción
2.- Ventanas: la clase Frame
3.- Componentes Básicos
4.- Eventos de teclado y de ratón
5.- Estilos
6.- Dibujando
7.- Applets
8.- Diálogos y mensajes
Apéndice A: Un poquito de Swing
1.1 AWT y SwingUna 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.
1.2 Un poco de filosofía
1.3 La jerarquía Component
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.AWT
Swing
|
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? |
El concepto básico de la programación gráfica es el componente. Un componente es cualquier cosa que tenga un tamaño una posición, pueda pintarse en pantalla y pueda recibir eventos (es decir, pueda recibir acciones por parte del usuario). Un ejemplo típico es un botón; el evento más normal que puede recibir es que el usuario de la aplicación pulse el botón. Podemos resumir los conceptos básicos de la programación gráfica con AWT:
Observación: Por cada componente en AWT, el correspondiente componente en Swing suele tener el mismo nombre pero precedido de una letra J. Por ejemplo, los botones se representan en AWT mediante objetos de la clase Button y en Swing mediante objetos de la clase JButton, las ventanas mediante las clases Frame y JFrame, y así sucesivamente.
Todos los componentes son o bien contenedores (como Frame) o bien componentes básicos (como Button).
Los componentes básicos siempre deben formar parte de un contenedor para ser visibles.
Los contenedores a su vez se pueden insertar en otros contenedores.
La posición de un componente en un contenedor depende del tamaño del contenedor y de su estilo (Layout).
Todo componente incluye un atributo de tipo Graphicsque se encarga de dibujarlo cuando hace falta. Si queremos dibujar en el componente tendremos que pedirle que nos "deje" su objeto de tipo Graphics.
Si queremos que un componente haga algo cuando le ocurra un evento determinado debemos pasarle un objeto tipo Listener al que él avisará llegado el momento.
| 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 alto) | Para modificar el tamaño del componente |
| 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 |
| void setEnabled(Boolean) | Activa/desactiva el componente (útil para botones y opciones de menú) |
| Graphics getGraphics() | Devuelve el objeto tipo Graphics que puede dibujar en el componente |
| repaint() | Llamaremos a este método para pedirle al componente que se redibuje |
| repaint(int x, int y, int width, int height) | Llamaremos a este método para pedirle al componente que redibuje el rectángulo indicado |
| void Paint(Graphics g) | Redefiniremos este método (usando herencia) cuando queramos dibujar algo en el componente |
| void Update(Graphics g) | Método que por defecto borra el componente y llama a paint() cuando hay que repintar un componente. Se utiliza sobre todo en animaciones |
| Point3 getLocation() | Indica la posición de la esquina superior izquierda del componente en su contenedor |
| void setLocation(int x, int y) | Mueve el componente a la posición indicada |
| void setLocation(Point p) | Mueve el componente a la posición indicada |
| Container getParent() | Indica a qué contenedor pertenece el componente |
// Arial de 12 pts en negrita
Font fuenteNegrita = new Font("Arial",Font.BOLD,12);
| Componentes Básicos | |
|---|---|
| Clase | Descripción |
| Button | Botones con un texto (Ej: Aceptar) |
| Canvas | Rectángulo para dibujar |
| Choice | Lista desplegable (ej: lista de países para elegir) |
| CheckBox | Casillas cuadradas para marcar (como en un test) |
| Label | Etiqueta: caracteres que se muestran en un contenedor |
| List | Lista, similar a Choice pero constantemente desplegada |
| Scrollbar | Barra de desplazamiento |
| TextField | Campo de edición que puede utilizar el usuario para introducir datos |
| TextArea | Similar a TextField pero permite introducir texto que ocupe varias líneas |
| Contenedores | |
|---|---|
| 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 |
| Dialog | Ventana que se muestra sobre la ventana actual (Ej.: la típica ventana para preguntar "¿Está seguro de ...." y dos botones de Aceptar y Cancelar) |
| FileDialog | Similar al anterior, pero especializado para la selección de ficheros (se suele utilizar en las opciones de "Abrir" o "Grabar como" ) |
2.1 Abriendo las ventanasLa 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.
2.2 Cerrando las ventanas
2.3 Ejemplo
2.4 Utilización de la herencia
Para crear e inicializar una ventana AWT (Frame) vamos a seguir los siguientes pasos:
Aviso: No es posible explicar en un espacio limitado todas las características de un componente visual complejo como Frame, o como el resto de los estudiados en este tema. Por tanto nos limitaremos a los aspectos básicos, pero avisando de que en la ayuda de Java se pueden encontrar métodos, constructoras, etc. no discutidos aquí.
Crear la variable tipo Frame
Para eso utilizaremos alguna de las constructoras de la clase, que son:
- Frame(): Constructora sin parámetros; crea una ventana sin título
- Frame(String): Crea una ventana con el título que se le indica Por ejemplo:
Frame ventana = new Frame("Ventana de prueba");
Tamaño y posición iniciales
El tamaño se fija con el método void setSize(int, int) y la posición con setLocation(int,int). Ambos pertenecen a la clase Component. Ejemplo:ventana.setSize(300, 100); ventana.setLocation(100,50);Hay que observar que el tamaño y la posición dependen de la configuración de la pantalla. Para conocer el tamaño en pixels de la pantalla podemos utilizar el métodoToolkit.getDefaultToolkit().getScreenSize();, que devuelve un objeto de tipo Dimension. Por ejemplo, para que la ventana aparezca centrada y ocupe un tercio de la pantalla tanto en ancho como en alto podemos escribir: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; ventana.setSize(ancho, alto); ventana.setLocation(d.width/2-ancho/2,d.height/2-alto/2);
Otras inicializaciones (opcional)
También podemos fijar los colores, el tipo de letra, el título (con void setTitle(String))
o el icono que mostrará la ventana al minimizarse (con void setImage(Image)). Por ejemplo:
ventana.setBackground(new Color(20,140,10));
ventana.setForeground(Color.blue);
Font fuente = new Font("Arial", Font.PLAIN, 20);
ventana.setFont(fuente);
ventana.setTitle("Ejemplo de ventana ");
Fijar el estilo (opcional)
Hablaremos de los "estilos" más adelante. De momento baste con decir que el método setLayout(Layout) determina el estilo de la ventana, es decir cómo se distribuyen los componentes en la ventana. Por ejemplo:FlowLayout estilo = new FlowLayout(); ventana.setLayout(estilo);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.
Incorporar los componentes
En este paso se añaden los componentes que se desee incluir en la ventana. Para eso se utiliza el método void add(Component) heredado de la clase Container. Por ejemplo:Label etiq = new Label("Te estoy mirando..."); ventana.add(etiq);
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.Una ventana puede recibir los siguientes tipos de eventos:ventana.setVisible(true);
Aviso: Un error habitual es olvidar este paso con lo que la ventana no se mostrará
Observación: La utilización de setVisible permite "cambiar" de una ventana a otra, haciendo visible la que estaba oculta y viceversa.
Poniendo todo el código anterior junto obtenemos la siguiente ventana:
![]()
Escribir una clase para atenderlos. Esta clase
debe heredar de WindowAdapter o bien implementar el interfaz
WindowListener
Pasarle a la ventana un objeto de ese tipo a la
ventana mediante el método addWindowListener.
La ventana llamará al método adecuado correspondiente a cada evento.
class ParaAcabar extends WindowAdapter {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
Y el código para que la ventana utilice este método:
ParaAcabar acabar = new ParaAcabar();
ventana.addWindowListener(acabar);
Observación: Si en lugar de heredar de WindowAdapter hubiéramos implementado su interfaz correspondiente (WindowListener) habríamos tenido que incluir todos los métodos anteriores en la clase, aunque sólo estemos interesados en uno de ellos.
El siguiente programa reúne todos los conceptos anteriores:
Observación: En swing el componente correspondiente se llama JFrame, y permite indicar que se quiere salir de la aplicación al cerrar la ventana sin necesidad de escribir un objeto escucha, simplemente con:
JFrame ventana = new ... .... ventana.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
import java.awt.*;
import java.awt.event.*;
public class Principal {
public static void main(String[] args) {
// objeto de tipo ventana
Frame ventana = new Frame("Ventana de prueba");
// 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;
ventana.setSize(ancho, alto);
ventana.setLocation(d.width/2-ancho/2,d.height/2-alto/2);
// colores, título y fuente
ventana.setBackground(new Color(20,140,10));
ventana.setForeground(Color.blue);
Font fuente = new Font("Arial", Font.PLAIN, 20);
ventana.setFont(fuente);
ventana.setTitle("Ejemplo de ventana ");
// estilo
FlowLayout estilo = new FlowLayout();
ventana.setLayout(estilo);
// componentes
Label etiq = new Label("Te estoy mirando...");
ventana.add(etiq);
// añadimos el "listener" para cerrar la ventana
ParaAcabar acabar = new ParaAcabar();
ventana.addWindowListener(acabar);
// hacemos la ventana visible
ventana.setVisible(true);
}
}
// clase escucha que se ejecuta al tratar de cerrar la ventana
class ParaAcabar extends WindowAdapter {
public void windowClosing(WindowEvent e) {
System.exit(0); // abandonar la aplicación
}
}
Es interesante observar que la clase para cerrar la ventana se encuentra, por comodidad,
en el mismo fichero que la clase principal. Esto es posible porque esta clase
no es pública.
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.
2.4 Utilización de la herencia
import java.awt.*;
import java.awt.event.*;
public class Ventana extends Frame {
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);
// colores, título y fuente
setBackground(new Color(20,140,10));
setForeground(Color.blue);
Font fuente = new Font("Arial", Font.PLAIN, 20);
setFont(fuente);
setTitle("Ejemplo de ventana ");
// estilo
FlowLayout estilo = new FlowLayout();
setLayout(estilo);
// componentes
Label etiq = new Label("Te estoy mirando...");
add(etiq);
// añadimos el "listener" para cerrar la ventana
ParaAcabar acabar = new ParaAcabar();
addWindowListener(acabar);
}
}
// clase escucha que se ejecuta al tratar de cerrar la ventana
class ParaAcabar extends WindowAdapter {
public void windowClosing(WindowEvent e) {
System.exit(0); // abandonar la aplicación
}
}
De esta forma la clase ventana tiene todos los métodos de la clase Frame
más todos los que nosotros añadamos posteriormente.
La clase principal queda simplemente:
public class Principal {
public static void main(String[] args) {
// objeto de tipo ventana
Ventana ventana = new Ventana();
// hacemos la ventana visible
ventana.setVisible(true);
}
}
y en el resto del capítulo a menudo la omitiremos para evitar repetir el código,
que es independiente de la ventana.
3.1 Etiquetas: la clase LabelLa clase Label(etiqueta) se utiliza para mostrar Strings en un componente.
3.2 Botones: la clase Button
3.3 Entrada de datos: la clase TextField
3.4 Áreas de texto: la clase TextArea
3.5 Marcas casillas: la clase Checkbox
Constructoras
Tiene 3 constructoras:
- Label(): La constructora por defecto, crea una etiqueta con un String vacío.
- Label(String etiq): Etiq es el String a mostrar.
- Label(String etiq, int alineamiento): Permite indicar si la etiqueta se mostrará en el espacio reservado para ella en el component alineada a la izquierda (constante Label.LEFT), a la derecha (Label.RIGHT) o centrada (Label.CENTER).
Métodos
Aparte de los métodos heredados de Object y Component, esta clase tiene dos métodos importantes:
- setText(String etiq): Para modificar el contenido de la etiqueta.
- String getText(): Devuelve el contenido actual de la etiqueta.
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:
- void setLabel(String label) : Cambia la etiqueta del botón.
- String getLabel() : Devuelve la etiqueta actual.
- void setActionCommand(String command): Asocia un String al botón. Este String no se mostrará por pantalla, sino que se utilizará como identificador del botón.
- void addActionListener(ActionListener l): Para añadir una escucha que pueda reaccionar cuando se pulsa el botón. Se explica en el apartado siguiente.
Ventana.java
package ventanas; import java.awt.*; import java.awt.event.*; public class Ventana extends Frame { Button botón; Label etiq; // 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); // añadimos el "listener" para cerrar la ventana addWindowListener(new ParaAcabar()); } } // clase para cerrar la ventana class ParaAcabar extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } }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:El interfaz ActionListener tiene un sólo método: void actionPerformed(ActionEvent e), al que se invocará cuando ocurra un evento sobre el botón (normalmente que ha sido pulsado). El objeto ActionEvent nos servirá para saber más información acerca del evento, y normalmente se us cuando el mismo objeto de tipo ActionListener se utiliza de escucha para más de un botón, ya que nos permite saber cuál de los botones ha sido pulsado. En particular contiene 2 métodos que pueden ser útiles.
- Escribir una clase adecuada a la que pertenecerá el objeto escucha. Esta clase debe, en el caso de los botones, implementar el interfaz java.awt.event.ActionListener.
- Declarar un objeto del tipo anterior (normalmente en la constructora de la ventana, a la vez que se crea el botón).
- Asociar el objeto de tipo escucha con el botón o, dicho con la terminología habitual de Java, registrar el objeto como escucha del botón. Esto se hace utilizando el método void addActionListener(ActionListener l).
El siguiente ejemplo hace que el botón, al ser pulsado escriba por pantalla el mensaje "Gracias".
- String getActionCommand() .
- Object getSource(): Fuente del evento (objeto de tipo Button).
Ventana.java
package ventanas; import java.awt.*; import java.awt.event.*; public class Ventana extends Frame { Button botón; Label etiq; // constructora public Ventana() { // titulo, estilo, tamaño y posición iniciales setTitle("Ejemplo de ventana con boton (v.2) "); 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); // preparamos la escucha del boton Escucha e = new Escucha(); // la registramos botón.addActionListener(e); // añadimos la escucha para cerrar la ventana addWindowListener(new ParaAcabar()); } } // clase para cerrar la ventana class ParaAcabar extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } } // escucha del boton class Escucha implements ActionListener { public void actionPerformed(ActionEvent e) { System.out.println("Gracias"); } }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); ^La razón es que la variable boton no es visible dentro de la clase Escucha. Afortunadamente podemos obtener el botón a partir de la variable ActionEvent e de la siguiente forma:// escucha del boton class Escucha implements ActionListener { public void actionPerformed(ActionEvent e) { Button boton = (Button) e.getSource(); // 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); } }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:
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.
Definir un atributo en la clase escucha que contendrá una referencia al componente externo deseado.
Este atributo se inicializará mediante la constructora.
En nuestro caso:Ventana.java
package ventanas; import java.awt.*; import java.awt.*; import java.awt.event.*; public class Ventana extends Frame { // constructora public Ventana() { // titulo, estilo, tamaño y posición iniciales setTitle("Ejemplo de ventana con boton (v.3) "); setLayout(new FlowLayout()); setSize(300, 100); setLocation(100,50); // le damos un poco de color a la ventana setBackground(Color.yellow); // una etiqueta Label etiq = new Label("Aún no has pulsado"); add(etiq); // creamos el boton Button boton = new Button("Púlsame"); boton.setBackground(Color.blue); boton.setForeground(Color.white); // incorporamos el boton al frame // importante: si no se hace esto no sera visible add(boton); // preparamos la escucha del boton Escucha e = new Escucha(etiq); // la registramos boton.addActionListener(e); // añadimos el "listener" para cerrar la ventana addWindowListener(new ParaAcabar()); // la mostramos setVisible(true); } } // clase para cerrar la ventana class ParaAcabar extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } } // escucha del boton class Escucha implements ActionListener { int i; // para contar las veces que se ha pulsado Label etiqueta; // etiqueta que se modificará public Escucha(Label etiqueta) { this.etiqueta = etiqueta; i=0; } public void actionPerformed(ActionEvent e) { i++; etiqueta.setText("Has pulsado "+i+" veces"); } }Ahora sí que el programa funcionará correctamente:![]()
Escribir la clase escucha dentro de la clase Ventana.
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:package ventanas; import java.awt.*; import java.awt.*; import java.awt.event.*; public class Ventana extends Frame { private int contador; private Label etiq; private Button botón; // constructora public Ventana() { contador = 0; // titulo, estilo, tamaño y posición iniciales setTitle("Ejemplo de ventana con boton (v.3) "); 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("Aún no has pulsado"); add(etiq); // creamos el boton botón = new Button("Púlsame"); botón.setBackground(Color.blue); botón.setForeground(Color.white); // incorporamos el boton al frame // importante: si no se hace esto no sera visible add(botón); // preparamos la escucha del boton Escucha e = new Escucha(); // la registramos botón.addActionListener(e); // añadimos el "listener" para cerrar la ventana addWindowListener(new ParaAcabar()); } // escucha del botón private class Escucha implements ActionListener { public void actionPerformed(ActionEvent e) { contador++; etiq.setText("Has pulsado "+contador+" veces"); } } } // fin de la clase Ventana // clase para cerrar la ventana class ParaAcabar extends WindowAdapter { public void windowClosing(WindowEvent e) {System.exit(0);} }
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: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:
- Escribir dos clases escucha, una para el botón de incrementar y otra para el de decrementar.
- Utilizar la misma escucha para ambos.
Ventana.java
package ventanas; import java.awt.*; import java.awt.*; import java.awt.event.*; public class Ventana extends Frame { // constructora public Ventana() { // titulo, estilo, tamaño y posición iniciales setTitle("contadores "); setLayout(new FlowLayout()); setSize(200, 100); setLocation(100,50); // le damos un poco de color a la ventana setBackground(Color.yellow); // las etiquetas Font fuente = new Font("Arial", Font.PLAIN, 20); Label etiq = new Label("Contador: "); etiq.setFont(fuente); add(etiq); Label etiq2 = new Label("0"); etiq2.setFont(fuente); add(etiq2); // preparamos la escucha del boton Escucha e = new Escucha(etiq2); // creamos los botones Button botonInc = new Button("Incremento"); botonInc.setActionCommand("inc"); botonInc.setBackground(Color.blue); botonInc.setForeground(Color.white); add(botonInc); botonInc.addActionListener(e); Button botonDec = new Button("Decremento"); botonDec.setActionCommand("dec"); botonDec.setBackground(Color.red); botonDec.setForeground(Color.white); add(botonDec); botonDec.addActionListener(e); // añadimos el "listener" para cerrar la ventana addWindowListener(new ParaAcabar()); } } // clase para cerrar la ventana class ParaAcabar extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } } // escucha del boton class Escucha implements ActionListener { int contador; // para contar las veces que se ha pulsado Label etiqueta; // etiqueta que se modificará public Escucha(Label etiqueta) { this.etiqueta = etiqueta; contador=0; } public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("inc")) contador++; else contador--; etiqueta.setText(" "+contador+" "); } }El programa tendrá el siguiente aspecto:![]()
3.3 Entrada de datos: la clase TextField
Constructoras
Para TextField:
- TextField(): Constructora por defecto conteniendo la cadena vacía y con 0 columnas.
- TextField(int columnas): Contenido vacío pero longitud prefijada inicial.
- TextField(String texto) Campo de texto con un valor inicial.
- TextField(String texto, int columnas): Las dos anteriores combinadas.
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:
- setEchoChar(Char c): Indica el carácter que aparece cuando se introduce un valor y se usa para introducir palabras clave. setEchoChar(0) hace que el carácter que aparece sea el carácter pulsado.
- setEditable(boolean): Si se pone a false no se podrá escribir sobre el campo de edición.
- int getSelectionStart(), int getSelectionEnd(): Para saber el trozo de texto que ha sido seleccionado por el usuario. Muy útil para las acciones de "Copiar", "Cortar" y "Pegar".
- void setSelectionStart(int inicio), void setSelectionEnd(int fin): Para marcar una porción de texto. En realidad setSelectionEnd(int fin) indica una posición más allá de la última a marcar. Por ejemplo, para marcar los caracteres 2,3 y 4 (tercer, cuarto y quinto carácter) se utilizaría:
texto.setSelectionStart(2); texto.setSelectionEnd(5);
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:
package claves;
import java.awt.*;
import java.awt.event.*;
public class PalabraClave extends Frame {
private Label etiq,etiq2,etiq3;
private Button aceptar;
private TextField login;
private TextField pass;
public PalabraClave() {
// titulo, estilo, tamaño y posición iniciales
setTitle("Entrada al Sistema");
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);
// preparamos la entrada de datos
etiq = new Label("Login: ");
add(etiq);
login = new TextField(8);
add(login);
etiq2 = new Label("Password:");
etiq2.setFont(fuente);
add(etiq2);
pass = new TextField(10);
pass.setEchoChar('*');
add(pass);
aceptar = new Button("Aceptar");
add(aceptar);
etiq3 = new Label("Pulsa Aceptar para Continuar");
add(etiq3);
// preparamos las escuchas
EscuchaAceptar e = new EscuchaAceptar();
aceptar.addActionListener(e);
pass.addActionListener(e);
// esta vale sólo para el campo de login
EscuchaSiguiente pasaAlSiguiente = new EscuchaSiguiente();
login.addActionListener(pasaAlSiguiente);
// añadimos la escucha para cerrar la ventana
addWindowListener(new ParaAcabar());
}
// escuchas como subclases privadas ///////////////////////
// escucha del boton Aceptar
private class EscuchaAceptar implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (válidos(login.getText(), pass.getText()))
etiq3.setText("Datos válidos");
else
etiq3.setText("Datos no válidos");
}
private boolean válidos(String login, String pass) {
// aquí se comprueba
return login.equals("Bertoldo") && pass.equals("nolose");
}
}
// clase escucha para el primer campo de edición; le pasa el foco
// al siguiente
private class EscuchaSiguiente implements ActionListener {
public void actionPerformed(ActionEvent e) {
// componente sobre el que ha ocurrido el evento
Component c = (Component) e.getSource();
// indicarle que pase el foco al siguiente elemento
c.transferFocus();
}
}
////////////////////// fin escuchas //////////////////////////////
} // Ventana
// clase para cerrar la ventana
class ParaAcabar extends WindowAdapter {
public void windowClosing(WindowEvent e) {System.exit(0);}
}
La ejecución del programa tendrá el siguiente aspecto:
3.4 Áreas de texto: la clase TextArea
Constructoras
- TextArea(): Área de texto con una cadena vacía. Tamaño de alrededor de 55 filas por 15 columnas
- TextArea(int filas, int columnas): Fija el número de filas y columnas. Si el número excede el tamaño del TextArea se incluyen automáticamente las barras de desplazamiento.
- TextArea(String texto): Texto inicial.
- TextArea(String texto, int filas, int columnas): Texto inicial con filas y columnas prefijadas.
- TextArea(String texto, int filas, int columnas, int barras): Añade al anterior la posibilidad de controlar la existencia de barras de desplazamiento. Los posibles valores de barras son:
- SCROLLBARS_BOTH
- SCROLLBARS_HORIZONTAL_ONLY
- SCROLLBARS_NONE
- SCROLLBARS_VERTICAL_ONLY
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.
3.5 Marcar casillas: la clase Checkbox
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 class Ventana extends Frame { // la ventana contiene 4 casillas private Checkbox casilla1,casilla2,casilla3,casilla4; // dos etiquetas Label etiq1, etiq2; // y un botón private Button aceptar; 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) ; etiq1 = new Label("Marque sus aficiones favoritas y pulse Aceptar"); add(etiq1); // una forma de construir una casilla casilla1 = new Checkbox(); casilla1.setLabel("Deportes"); // otra forma casilla2 = new Checkbox("Lectura"); casilla3 = new Checkbox("Viajes"); casilla4 = new Checkbox("Cine"); // hacemos que la casilla Cine aparezca marcada casilla4.setState(true); add(casilla1); add(casilla2); add(casilla3); add(casilla4); aceptar = new Button("Aceptar"); add(aceptar); // escucha del botón aceptar.addActionListener(new EscuchaBotón()); // etiqueta donde se mostrará el resultado etiq2 = new Label(""); // añadimos la escucha para cerrar la ventana addWindowListener(new ParaAcabar()); } ////////////////////////////////////////////////////// // 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()+" "; // añadimos a la ventana un label con los objetos elegidos add(new Label(aficiones)); } } } // clase escucha que se ejecuta al tratar de cerrar la ventana class ParaAcabar extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); // abandonar la aplicación } }El resultado es:
![]()
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 class Ventana extends Frame { // grupo de 3 casillas private CheckboxGroup grupo; private Checkbox c1,c2,c3; // y una etiqueta Label etiq1; 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) ; etiq1 = new Label("Destino:"); add(etiq1); // primero se construye el "agrupador" grupo = new CheckboxGroup(); // ahora se crean las casillas indicando que están en el grupo c1 = new Checkbox("Madrid",grupo,false); c2 = new Checkbox("París",grupo,false); c3 = new Checkbox("Berlín",grupo,true); // añadir las casillas a la ventana; el grupo NO se añade add(c1); add(c2); add(c3); // añadimos la escucha para cerrar la ventana addWindowListener(new ParaAcabar()); } } // clase escucha que se ejecuta al tratar de cerrar la ventana class ParaAcabar extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); // abandonar la aplicación } }El resultado es:
![]()
4.- Eventos de teclado y de ratón
4.1 Eventos de tecladoLos eventos de teclado detectan la pulsación de teclas. Cualquier componente puede registrar una escucha de teclado, al igual que una escucha para el ratón. El componente que recibe la entrada de teclado en cada momento es único; se dice que ese componente "tiene el foco". Un componente puede pedir el foco utilizando el método requestFocus(). Para detectar los eventos de teclado, un componente debe:
4.2 Eventos de ratón
El interfaz KeyListener dispone de los siguientes métodos:Escribir una clase que implemente el interfaz KeyListener.
Declarar un objeto de la clase anterior.
Registrarlo con addKeyListener(KeyListener escucha), un método de la clase Component.
import java.awt.*;
import java.awt.event.*;
public class Teclas extends Frame {
private Label etiq; // único componente
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);
// preparamos la entrada de datos
etiq = new Label("Pulsa 'S' para salir ");
add(etiq);
// escucha de teclado para la ventana;
// le pasamos como parámetro la etiqueta
EscuchaTeclas e = new EscuchaTeclas(etiq);
addKeyListener(e);
// añadimos la escucha para cerrar la ventana
addWindowListener(new ParaAcabar());
// si no hacemos esto el foco se lo queda la etiqueta!!!
requestFocus();
}
}
// clase para cerrar la ventana
class ParaAcabar extends WindowAdapter {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
// escucha de teclaro
class EscuchaTeclas implements KeyListener {
private Label etiq;
public EscuchaTeclas(Label etiq) {
this.etiq = etiq;
}
public void keyPressed(KeyEvent e){
if (e.isActionKey()==false && e.getKeyChar() == 'S') {
System.exit(0);
} else {
// guardamos el código de la tecla especial
int tecla = e.getKeyCode();
// la posición actual de la etiqueta
Point pos = etiq.getLocation();
switch(tecla) {
case KeyEvent.VK_UP:
etiq.setLocation(pos.x,pos.y-1);
break;
case KeyEvent.VK_DOWN:
etiq.setLocation(pos.x,pos.y+1);
break;
case KeyEvent.VK_LEFT:
etiq.setLocation(pos.x-1,pos.y);
break;
case KeyEvent.VK_RIGHT:
etiq.setLocation(pos.x+1,pos.y);
break;
case KeyEvent.VK_NUM_LOCK:
etiq.setText("Bloque numérico");
break;
default:
}
}
}
// hay que incluir estos métodos aunque no se necesiten
public void keyReleased(KeyEvent e) { }
public void keyTyped(KeyEvent e) { }
}
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:La clase MouseEvent tiene entre otros métodos:
- void mouseClicked(MouseEvent e): Se ha pulsado el ratón.
- void mouseEntered(MouseEvent e): El ratón se ha situado sobre un componente (aunque no se haya pulsado).
- void mouseExited(MouseEvent e): El ratón abandona el componente sobre el que estaba situado.
- void mousePressed(MouseEvent e): Se ha pulsado un botón del ratón.
- void mouseReleased(MouseEvent e): Se ha soltado un botón del ratón que estaba pulsado.
Ejemplo: Vamos a mover un botón para que el usuario no pueda pulsarlo nunca:
- int getX() : coordenada x del ratón.
- int getY() : : coordenada y del ratón.
- Point getPoint() : posición del ratón.
- int getClickCount() : Informa sobre el número de pulsaciones, para distinguir el "doble-click".
- int getButton() : Informa sobre el botón que ha cambiado de estado. Puede devolver las constantes: BUTTON1, BUTTON2, BUTTON3.
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); // preparamos la entrada de datos Button botón = new Button("Púlsame"); add(botón); // escucha de teclado para la ventana EscuchaRatón e = new EscuchaRatón(botón); botón.addMouseListener(e); // añadimos la escucha para cerrar la ventana addWindowListener(new ParaAcabar()); // la mostramos setVisible(true); // si no hacemos esto el foco se lo queda la etiqueta!!! requestFocus(); } } // clase para cerrar la ventana class ParaAcabar extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } } class EscuchaRatón implements MouseListener { Button botón; // le pasamos el botón y el tamaño de la pantalla public EscuchaRatón(Button botón) { this.botón = botón; } public void mouseEntered(MouseEvent e) { Point p = botón.getLocation(); if (p.x<150) p.x = 160 + ((int)(Math.random()*120)); else p.x = 20 + ((int)(Math.random()*120)); p.y = 20 + ((int) (Math.random()*100)); botón.setLocation(p); } // no olvidar incluir estos métodos!! public void mouseClicked(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mousePressed(MouseEvent e) { } public void mouseReleased(MouseEvent e) { } }
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:
- void mouseMoved(MouseEvent e): El ratón se ha movido sin estar pulsado
- void mouseDragged(MouseEvent e): El ratón se ha movido estando pulsado.
5.1 IntroducciónEl estilo (o diseño) de un contenedor indica cómo se dispondrán los componentes básicos en él.
5.2 Estilo FlowLayout
5.3 Estilo BorderLayout
5.4 Estilo GridLayout
5.5 Paneles
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. En este estilo los componentes se colocan uno al lado del otro, en la misma fila. Cuando no caben más se cambia de fila. El orden en el que se colocan es de izquierda a derecha y de arriba a abajo. De los estilos sólo nos interesarán, en general, sus constructoras, no los métodos que contienen:
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.
Constructoras
Tiene 3 constructoras:Ejemplo: Añadimos 10 botones para ver como se colocan en la ventana con FlowLayout
- FlowLayout(): Constructora por defecto; cada fila se alinea al centro.
- FlowLayout(int alineamiento): Indica si cada fila aparecerá alineada al centro, a la izquierda o a la derecha. Para ello define las constantes FlowLayout.CENTER, FlowLayout.LEFT y FlowLayout.RIGHT.
- FlowLayout(int alineamiento, int sepH, int sepV) : Como el anterior, pero permitiendo indicar, además, la separación entre columnas y entre filas.
import java.awt.*;
import java.awt.event.*;
public class EstiloFlowLayout extends Frame {
public EstiloFlowLayout() {
// titulo, estilo, tamaño y posición iniciales
setTitle("FlowLayout");
setBackground(Color.cyan);
setSize(300,200);
// componentes centrados a la derecha, con una distancia entre ellos
// de 20 pixels en x y 30 en y
setLayout(new FlowLayout(FlowLayout.RIGHT, 20,30));
// añadimos unos botones de pega
for (int i=0; i<10; i++)
add(new Button(" "+i+" "));
// añadimos la escucha para cerrar la ventana
addWindowListener(new ParaAcabar());
}
}
// clase para cerrar la ventana
class ParaAcabar extends WindowAdapter {
public void windowClosing(WindowEvent e) {System.exit(0); }
}
Constructoras
- BorderLayout(): Constructora por defecto.
- BorderLayout(int sepHorizontal, int sepVertical): Incluye la separación en pixels entre los componentes.
Ejemplo
Es un estilo que divide el contenedor en "casillas". Permite fijar el número de componentes por fila y por columna. Todas las casillas serán del mismo tamaño, tamaño suficiente para que quepan todos los componentes.Ventana.java
import java.awt.*; import java.awt.event.*; public class Ventana extends Frame { public Ventana() { // titulo, estilo, tamaño y posición iniciales setTitle("BorderLayout"); setBackground(Color.cyan); setSize(300,200); // componentes centrados a la derecha, con una distancia entre ellos // de 20 pixels en x y 30 en y setLayout(new BorderLayout()); // creamos 5 botones Button este = new Button("Este"); este.setBackground(Color.blue); Button oeste = new Button("Oeste"); oeste.setBackground(Color.red); Button norte = new Button("Norte"); norte.setBackground(Color.yellow); Button sur = new Button("Sur"); sur.setBackground(Color.green); Button centro = new Button("Centro"); centro.setBackground(Color.pink); // añadimos botones en cada zona add(este, BorderLayout.EAST); add(oeste, BorderLayout.WEST); add(norte, BorderLayout.NORTH); add(sur, BorderLayout.SOUTH); add(centro); // equivalente a: add(centro, BorderLayout.CENTER); // añadimos la escucha para cerrar la ventana addWindowListener(new ParaAcabar()); } } // clase para cerrar la ventana class ParaAcabar extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } }El resultado es:![]()
Observación: Casi nunca se inserta un botón directamente en un componente con estilo BorderLayout. Lo normal es introducirlos en otro componente (por ejemplo en un Panel) que a su vez se inserta en el contenedor de estilo BorderLayout.
Constructoras
- GridLayout(): Constructora por defecto: una sola fila y una sola columna; poco usada.
- GridLayout(int filas, int columnas): Número de filas y columnas.
- GridLayout(int filas, int columnas, int sepHorizontal, int sepVertical): Además del tamaño en filas y columnas indica la separación horizontal y vertical entre los componentes.
Ejemplo
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.Grid.java
import java.awt.*; import java.awt.event.*; public class Grid extends Frame { public Grid() { // titulo, estilo, tamaño y posición iniciales setTitle("GridLayout"); setBackground(Color.yellow); setSize(250,150); // componentes en 4 filas, a 2 columnas, // 10 pixels de separación horizontal entre componentes // y 5 pixels de separación vertical setLayout(new GridLayout(4,2,10,5)); add(new Label("Nombre: ", Label.RIGHT)); TextField nombre = new TextField(10); add(nombre); add(new Label("Apellidos: ", Label.RIGHT)); TextField apellidos = new TextField(20); add(apellidos); add(new Label("Dirección: ", Label.RIGHT)); TextField dirección = new TextField(30); add(dirección); Button continuar = new Button("Siguiente"); add(continuar); Button abandonar = new Button("Cancelar"); add(abandonar); // faltarían todas las escuchas para que el programa haga algo real // añadimos la escucha para cerrar la ventana addWindowListener(new ParaAcabar()); } } // clase para cerrar la ventana class ParaAcabar extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } }El resultado es:![]()
Observación: Una fase importante al desarrollar aplicaciones con interfaz gráficos es la del diseño del interfaz: qué paneles compondrán cada ventana y con qué estilos.
import java.awt.*;
import java.awt.event.*;
public class Tablero extends Frame {
public Tablero() {
// titulo, estilo, tamaño y posición iniciales
setTitle("Tablero");
setBackground(Color.green);
// 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);
// preparamos el layout de la ventana
setLayout(new BorderLayout(20,20));
// 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);
// preparamos el tablero; será el panel central
Panel tablero = new Panel();
tablero.setLayout(new GridLayout(8,8));
for (int i=1; i<=8; i++)
for (int j=1; j<=8; j++)
if ((i+j) % 2 == 0) {
Button blanca = new Button(" ");
blanca.setBackground(Color.white);
blanca.setEnabled(false);
tablero.add(blanca);
}
else {
Button negra = new Button(" ");
negra.setBackground(Color.black);
negra.setEnabled(false);
tablero.add(negra);
}
// lo ponemos en el centro
add(tablero,BorderLayout.CENTER);
// tablero para los botones
Panel botones = new Panel();
Button empezar = new Button("Empezar");
Button acabar = new Button("Acabar");
// no dejamos que pulsen acabar si no se está jugando
acabar.setEnabled(false);
botones.add(empezar);
botones.add(acabar);
add(botones, BorderLayout.SOUTH);
// paneles para dejar margen a la izquierda y a la derecha
Panel izq = new Panel();
Panel der = new Panel();
add(izq,BorderLayout.EAST);
add(der,BorderLayout.WEST);
// añadimos la escucha para cerrar la ventana
addWindowListener(new ParaAcabar());
}
}
// clase para cerrar la ventana
class ParaAcabar extends WindowAdapter {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
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
¿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).
- Los objetos capaces de dibujar son los de tipo Graphics (descritos en el punto 4.6.3). Contienen métodos para dibujar líneas, rectángulos, imágenes leídas de un fichero (formato .gif o jpeg) etc.
- Todo componente gráfico contiene un objeto de tipo Graphics, que es el que usa para "dibujarse" a si mismo.
- Todo componente gráfico incluye un método Graphics getGraphics()
Ventana.java
import java.awt.*; import java.awt.event.*; public class Ventana extends Frame{ public Ventana() { // titulo, estilo, tamaño y posición iniciales setTitle("Botón con dibujo V.1"); setLayout(new FlowLayout()); Font fuente = new Font("Arial", Font.BOLD, 40); setFont(fuente); // 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); Button botón = new Button("Aceptar"); add(botón); // añadimos el "listener" para cerrar la ventana addWindowListener(new ParaAcabar()); // la mostramos setVisible(true); // dibujamos sobre el botón Graphics g = botón.getGraphics(); g.setColor(Color.green); g.fill3DRect(5,40,70,10,true); g.fill3DRect(80,40,90,10,true); } } // clase para cerrar la ventana class ParaAcabar extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } }
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.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: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).
- Cuando un objeto necesita repintarse, llama a su método public void update(Graphics g).
- El comportamiento por defecto de update es:
- Borrar el componente.
- Llamar al método public void paint(Graphics g) para dibujarlo de nuevo.
- Nosotros no podemos llamar a estos métodos directamente; pero podemos pedir a un componente que se "repinte" con el método public void repaint().
BotonSubrayado.java
import java.awt.*; public class BotonSubrayado extends Button { public BotonSubrayado(String nombre) { super(nombre); } public void paint(Graphics g) { // llamamos al pintar original super.paint(g); g.setColor(Color.green); g.fill3DRect(5,40,70,10,true); g.fill3DRect(80,40,90,10,true); } }
Ventana.java
import java.awt.*; import java.awt.event.*; public class Ventana extends Frame{ public Ventana() { // titulo, estilo, tamaño y posición iniciales setTitle("Botón con dibujo V.1"); setLayout(new FlowLayout()); Font fuente = new Font("Arial", Font.BOLD, 40); setFont(fuente); // 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); BotonSubrayado botón = new BotonSubrayado("Aceptar"); add(botón); // añadimos el "listener" para cerrar la ventana addWindowListener(new ParaAcabar()); // 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); } } // clase para cerrar la ventana class ParaAcabar extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } }Ahora cada vez que haya que volver a pintar el botón se dibujará también la línea
import java.awt.*;
// clase para dibujar
public class Lienzo extends Canvas {
...
// aquí se incluirá el código para dibujar
public void paint(Graphics g) {
....
}
.....
}
import java.awt.*;
import java.awt.event.*;
public class Ventana extends Frame {
......
public Ventana() {
....
....
Lienzo l = new Lienzo();
add(l);
.......
......
}
}
......
public class Principal {
public static void main(String[] args) {
new Ventana();
}
}
| 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);).
|
abstract boolean |
drawImage(Image img,
int x,
int y,
Color bgcolor,
ImageObserver observer)
Dibuja la imagen. Las coordenadas (x,y) marcan
donde estará situada la esquina superior izquierda del dibujo y bgcolor el fondo que se mostrará en la parte
transparente de la imagen. El parámetro observer indica un objeto al que se va avisando cuando según se va mostrando
la imagen. Nosotros lo lo utilizaremos y lo pondremos a null.
|
abstract boolean |
drawImage(Image img,
int x,
int y,
ImageObserver observer)
Análogo al anterior. El color de fondo no varía. |
abstract boolean |
drawImage(Image img,
int x,
int y,
int width,
int height,
bgcolor,
ImageObserver observer)
Análogo a los anteriores con la salvedad de que el gráfico se reescalará para ajustarse al rectángulo indicado. |
abstract boolean |
drawImage(Image img,
int x,
int y,
int width,
int height,
ImageObserver observer)
Análogo al anterior. |
abstract void |
drawLine(int x1,
int y1,
int x2,
int y2)
Dibuja una línea, en el color actual, entre los dos puntos.
|
abstract void |
drawOval(int x,
int y,
int width,
int height)
Dibuja un óvalo inscrito en el rectángulo indicado. Si width = height se dibujará una circunferencia |
abstract void |
drawPolygon(int[] x,
int[] y,
int n)
Dibuja un polígono. Para ello traza las rectas (x[0],y[0]), (x[1],y[1]) ... (x[n-2],y[n-2]), (x[n-1],y[n-1]), (x[n-1],y[n-1]), (x[0],y[0]). |
abstract void |
drawPolyline(int[] xPoints,
int[] yPoints,
int nPoints)
Dibuja una secuencia de líneas. La diferencia con drawPolygon es que no incluye la última línea para "cerrar" el polígono. |
void |
drawRect(int x,
int y,
int width,
int height)
Dibuja un rectángulo. |
abstract void |
drawRoundRect(int x,
int y,
int width,
int height,
int arcWidth,
int arcHeight)
Dibuja un rectángulo con los ángulos "redondeados". |
abstract void |
drawString(String str,
int x,
int y)
Muestra la cadena. El punto (x,y) representa la posición inicial (marcada por un punto en la figura de abajo) para el primer carácter de la cadena.
|
void |
fill3DRect(int x,
int y,
int width,
int height,
boolean raised)
Análogo a draw3DRect pero dibujando el rectángulo relleno con el color actual. |
abstract void |
fillArc(int x,
int y,
int width,
int height,
int startAngle,
int arcAngle)
Análogo a drawArc pero dibujando el arco relleno con el color actual. |
abstract void |
fillOval(int x,
int y,
int width,
int height)
Análogo a fillOval pero con el óvalo relleno del color actual. |
abstract void |
fillPolygon(int[] xPoints,
int[] yPoints,
int nPoints)
Análogo a drawPolygon pero rellenando el polígono con el color actual. |
abstract void |
fillRect(int x,
int y,
int width,
int height)
Análogo a drawRect pero rellenando el rectángulo del color actual. |
abstract void |
fillRoundRect(int x,
int y,
int width,
int height,
int arcWidth,
int arcHeight)
Análogo a drawRoundRect pero rellenando el rectángulo redondeado con el color actual. |
void |
finalize()
Para liberar la memoria requerida por un objeto Graphics que ya no es necesario. Esto se hace porque los objetos Graphics son muy costosos en cuanto a recursos de memoria. |
abstract Color |
getColor()
Devuelve el color actual. |
abstract Font |
getFont()
Devuelve la fuente (tipo de letra) actual. |
FontMetrics |
getFontMetrics()
Devuelve un valor de tipo FontMetrics representando las características métricas de la fuente de letra actual. La clase FontMetrics contiene diversos métodos para conocer las medidas de los caracteres dentro del tipo actual. Por ejemplo el método stringWidth(String cadena) devolverá la anchura en pixels requerida para mostrar la cadena. |
abstract FontMetrics |
getFontMetrics(Font f)
Devuelve las características métricas de la fuente de letra que se le pasa como parámetro. |
abstract void |
setColor(Color c)
Cambia el color actual al color indicado. |
abstract void |
setFont(Font font)
Establece la nueve fuente de letra. |
abstract void |
setPaintMode()
Indica que al dibujar se borra el fondo. Es el modo de actuación por defecto. |
abstract void |
setXORMode(Color c1)
Al dibujar los pixels que sean del color de fondo se cambian al color del parámetro y viceversa. |
String |
toString()
Representación como cadena de caracteres del objeto Graphics. |
abstract void |
translate(int x,
int y)
Fija un nuevo centro de coordenadas. |
| Image img = Toolkit.getDefaultToolkit().getImage("foto.gif"); |
import java.awt.*;
import javax.swing.*;
public class Saluda extends Canvas {
Image t[]; // array de imágenes
public Saluda() {
t = new Image[10];
for (int i = 0; i<10; i++)
t[i] = Toolkit.getDefaultToolkit().getImage("t"+(i+1)+".gif");
}
public void paint(Graphics g) {
g.drawImage(t[0],0,0, 200,200, Color.white, null);
}
public void saluda() {
Graphics g = getGraphics();
for (int i = 1; i<10; i++) {
g.drawImage(t[i],0,0,200,200, Color.white, null);
// perdemos un poco de tiempo para que se vea
try{ Thread.sleep(150);} catch(Exception e) {}
}
repaint();
}
}
import java.awt.*;
import java.awt.event.*;
public class Ventana extends Frame {
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);
// el lienzo irá en el centro de la pantalla
Saluda lienzo = new Saluda();
add(lienzo);
// el botón con su escucha correspondiente
Button boton = new Button("saluda!");
Escucha e = new Escucha(lienzo);
boton.addActionListener(e);
add(boton, BorderLayout.SOUTH);
// añadimos el "listener" para cerrar la ventana
addWindowListener(new ParaAcabar());
// la mostramos
setVisible(true);
}
}
// clase para cerrar la ventana
class ParaAcabar extends WindowAdapter {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
// escucha del boton
class Escucha implements ActionListener {
Saluda lienzo;
public Escucha(Saluda lienzo) {
this.lienzo = lienzo;
}
public void actionPerformed(ActionEvent e) {
lienzo.saluda();
}
}
public class Principal {
public static void main(String[] args) {
new Ventana();
}
}
Versión inicial
La idea es, como siempre, sobreescribir la clase paint del lienzo para que dibuje un circulo (la pelota), pero de forma que la posición de la pelota dependa de unas variables x, y, y escribir un método que modifique estas variables y obligue al lienzo a repintarse para simular la animación.
Principal.java
public class Principal { static public void main(String [] args) { new Ventana(); } }
Ventana.java
import java.awt.*; import java.awt.event.*; public class Ventana extends Frame { public Ventana() { // titulo, estilo, tamaño y posición iniciales setTitle("Animación - V1"); // ventana centrada Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); int ancho=400, alto=250; setSize(ancho, alto); setLocation(d.width/2-ancho/2,d.height/2-alto/2); // el lienzo irá en el centro de la pantalla CorrePelota lienzo = new CorrePelota(); add(lienzo); // añadimos el "listener" para cerrar la ventana addWindowListener(new ParaAcabar()); // la mostramos setVisible(true); // buclew de animación for (long i=0; i<10000000; i++) { // mover la pelota lienzo.correCorre(); // perder el tiempo try { Thread.sleep(10); } catch(Exception e) {} } } } // clase para cerrar la ventana class ParaAcabar extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } }
CorrePelota.java
import java.awt.*; public class CorrePelota extends Canvas { private final int radio = 30; int x = 20,y = 20; // pos. inicial int incX = 1, incY = 1; // dir. inicial public CorrePelota() { setBackground(Color.black); setForeground(Color.yellow); } public void correCorre() { // calculamos la nueva posición de la pelota x += incX; y += incY; // si hay choque invertimos la dirección if (x>370) incX = -((int) (Math.random()*2+1)); if (x<0) incX = (int) (Math.random()*2+1); if (y>190) incY = -((int) (Math.random()*2+1)); if (y<0) incY = (int) (Math.random()*2+1); repaint(); } public void paint(Graphics g) { g.fillOval(x,y,radio,radio); } }
El programa funciona, pero la pelota al moverse tiene un extraño "parpadeo". Vamos a ver como solucionarlo.
Yo me lo pinto y yo me lo borro
El problema es que antes de pintar el nuevo dibujo debe borrarse el anterior; y de eso se encarga update, que antes de llamar a paint borra el lienzo completo.
Como esto tarda en hacerse en ocasiones el refresco de pantalla "pilla" a la animación justo después de borrar la figura pero antes de volver a dibujarla y eso provoca el parpadeo. Una solución es impedir que update() borre la figura anterior y en su lugar hacerlo nosotros, que en lugar de borrar todo el gráfico sólo borraremos la figura anterior.
Para hacer esto sólo tenemos que modificar la clase CorrePelota:
CorrePelota.java
import java.awt.*; public class CorrePelota extends Canvas { private final int radio = 30; int x = 20,y = 20; // pos. inicial int incX = 1, incY = 1; // dir. inicial int antx, anty; // posición antigua de la pelota public CorrePelota() { setBackground(Color.black); setForeground(Color.yellow); } public void correCorre() { // guardamos la posición antigua para borrarla antx = x; anty = y; // calculamos la nueva posición de la pelota x += incX; y += incY; // si hay choque invertimos la dirección if (x>370) incX = -((int) (Math.random()*2+1)); if (x<0) incX = (int) (Math.random()*2+1); if (y>190) incY = -((int) (Math.random()*2+1)); if (y<0) incY = (int) (Math.random()*2+1); repaint(); } public void update(Graphics g) { paint(g); } public void paint(Graphics g) { // borramos la anterior g.clearRect(antx,anty,radio,radio); g.fillOval(x,y,radio,radio); } }
Aunque el parpadeo disminuye ligeramente sigue existiendo; se tarda demasiado en dibujar el óvalo.Doble buffer
La idea es no dibujar ni borrar directamente en la pantalla, sino en un objeto de tipo Image que nos hará de "buffer" o de copia del lienzo. Una vez que hayamos dibujado en el objeto sólo tendremos que volcarlo a pantalla con drawImage. Así el usuario no podrá ver el proceso de borrado y dibujado; sólo la figura en la nueva posición.
La nueva versión de la clase CorrePelota es:CorrePelota.java
import java.awt.*; public class CorrePelota extends Canvas { private final int radio = 30; int x = 20,y = 20; // pos. inicial int incX = 1, incY = 1; // dir. inicial int antx, anty; // posición antigua de la pelota // el doble buffer Image copia; Graphics gCopia; boolean primeraVez = true; public CorrePelota() { setBackground(Color.black); setForeground(Color.yellow); } public void correCorre() { // guardamos la posición antigua para borrarla antx = x; anty = y; // calculamos la nueva posición de la pelota x += incX; y += incY; // si hay choque invertimos la dirección if (x>370) incX = -((int) (Math.random()*2+1)); if (x<0) incX = (int) (Math.random()*2+1); if (y>190) incY = -((int) (Math.random()*2+1)); if (y<0) incY = (int) (Math.random()*2+1); repaint(); } public void update(Graphics g) { // para que la pinte paint(g); } public void paint(Graphics g) { if (primeraVez) { copia = createImage(400,250); gCopia = copia.getGraphics(); primeraVez = false; } gCopia.clearRect(antx,anty,radio,radio); gCopia.fillOval(x,y,radio,radio); g.drawImage(copia,0,0,this); } }
Observación: En swing existen métodos específicos para tratar el doble buffer que permiten mostrar animaciones de mejor calidad.
7.1 ¿Qué es un Applet?Un applet es un programa Java que se ejecuta dentro de una página html. El código (.class) viaja junto con la página al ordenador del usuario, donde es ejecutado por la máquina virtual del explorador correspondiente.
7.2 Páginas WEB
7.3 Vida (y muerte) de un Applet
7.4 Ejemplo
Los applets son especialmente utilizados en páginas de tipo científico y pedagógicas, para ilustrar conceptos, simular experimentos. Un ejemplo típico es cuando en nuestra página queremos mostrar un gráfica que depende de ciertos parámetros introducidos por el usuario.
Observación: Para que se pueda ver el applet dentro de la página hay que tener activada la máquina virtual de Java del explorador
Páginas html
Una página WEB es, normalmente un texto escrito en el lenguaje html. La forma más simple de una página en html es
pagina.html<html> <head> <title> Una página </title> </head > <body > Esta es una página mínima </body> </html>Podemos escribir este texto en un fichero (por ejemplo con el block de notas), grabarlo y abrirlo con el explorador. En general una página html puede contener:Sin embargo no puede incluir acciones dinámicas, como por ejemplo pedir datos al usuario, procesarlos y mostrar el resultado, o mostrar una animación
- Texto (se incluye el texto sin más)
- Imágenes (Ej.: <img src="dibu.jpg"> para incluir dibu.jpg en la página )
- Enlaces a otras páginas (Ej.: Si incluimos <a href="http://www.ucm.es">ucm</a> aparecerá la palabra ucm y al pulsar sobre ella se saltará a la página de la universidad complutense).
Incluyendo Java en páginas WEB
La llamada al código java se introduce mediante el delimitador html applet<html> <head> <title> Un mini-applet </title> </head > <body > Aquí incluimos una llamada al applet: <p> <applet code=“Mini.class" width=150 Height=25></applet> <p> Y luego seguimos con el texto de la página </body> </html>El resultado es:
![]()
Importante: El código java compilado (Mini.class en el ejemplo) debe encontrarse en la misma carpeta que la página html.
7.3 Vida (y muerte) de un Applet
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class Imagen extends Applet implements Runnable{
Image coche;
int x=600,y=20;
Thread corre = new Thread(this);
//Inicializar el applet
public void init() {
MediaTracker tracker = new MediaTracker(this);
coche = getImage(getCodeBase(),"cab.gif");
tracker.addImage(coche, 1);
try { tracker.waitForAll();} catch(Exception e) {e.printStackTrace();}
this.setBackground(Color.white);
}
public void run() {
try {
Thread.sleep(1000);
} catch (Exception e) {;}
while (true) {
repaint();
try {
Thread.sleep(40);
} catch (Exception e) {;}
}
}
public void start() {
corre.start();
}
public void paint(Graphics g) {
update(g);
}
public void update(Graphics g) {
x--;
g.drawImage(coche,x,y,70,50,Color.white,this);
if (x==-70) x = 600; // volvemos a empezar
}
}
8.1 La clase DialogLos 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:
8.2 La clase FileDialog
8.3 La clase JOptionPane
Constructoras
Es un caso especial de diálogo modal orientado a la selección de ficheros (a menudo asociados a opciones del estilo de "Abrir" o "Guardar como"). Hay que tener en cuenta que el diálogo sólo selecciona nombres de ficheros; no abre ni guarda nada.
- Dialog(Frame prop): Crea un diálogo no visible (hasta que se haga setVisible(true)), no modal y con título vacío. prop es el nombre del diálogo o la ventana propietaria. Si se desea se puede poner null para indicar que no tiene ventana "madre".
- Dialog(Frame prop, String titulo): Análogo al anterior pero indicando el título.
- Dialog(Frame prop, String titulo, boolean modal): Si modal es true crea una ventana modal.
Constructoras
La constructora más completa tiene la sintaxis:
FileDialog(Frame vent, String msg, int mode)
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
El siguiente ejemplo ilustra como se puede utilizar este diálogo para abrir un fichero:Además de estos métodos es interesante conocer la constante File.separator que indica el separador de directorios (la barra inclinada hacia la derecha o la izquierda dependiendo del sistema operativo).
- String getDirectory(): Cadena con el directorio que contiene el fichero seleccionado.
- String getFile(): Cadena con el nombre del fichero seleccionado.
- FilenameFilter getFilenameFilter(): Filtro utilizado en la selección.
- int getMode(): Devuelve el modo: FileDialog.LOAD o FileDialog.SAVE.
- void setDirectory(String dir) : Establece el directorio inicial que se mostrará al abrir el diálogo.
- void setFile(String nombreFich): Nombre por defecto del fichero; se usa habitualmente en los diálogos de guardar.
- void setFilenameFilter(FilenameFilter f): Filtro que se utilizará para mostrar los archivos en el cuadro de diálogo.
- void setMode(int modo): Pone el modo a FileDialog.LOAD o FileDialog.SAVE.
import java.awt.*;
import java.awt.event.*;
public class Ventana extends Frame {
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);
// añadimos el "listener" para cerrar la ventana
addWindowListener(new ParaAcabar());
// la mostramos
setVisible(true);
// creamos un dialogo para abrir un fichero
FileDialog fd = new FileDialog(this, "Abrir...",FileDialog.LOAD);
// al abrir el dialogo, como es modal, la aplicación queda
// bloqueada
fd.setVisible(true);
String fname = fd.getFile();
// si el usuario ha cancelado el dialogo se devuelve null
if (fname != null) {
String fdir = fd.getDirectory();
String name = fdir + fname;
// mostramos el nombre elegido en la ventana
etiqSel.setText(name);
} // if
}
}
// clase para cerrar la ventana
class ParaAcabar extends WindowAdapter {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
Los principales métodos de esta clase son cuatro métodos estáticos:
Observación: Es posible (y bastante normal) mezclar en una misma aplicación componentes awt con componentes swing.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*; // para JOptionPane
public class Ventana extends Frame {
public Ventana() {
setTitle("Entrada de datos");
setLayout(new FlowLayout());
setSize(200,100);
setLocation(300,200);
// el primer argumento es la ventana madre,
// el segundo el mensaje a mostrar, el tercero el titulo
// de la ventana y el cuarto el tipo de dialogo
JOptionPane.showMessageDialog(this,
"El fichero se ha grabado correctamente",
"informacion", JOptionPane.INFORMATION_MESSAGE);
// muestra el dialogo con un simbolo de interrogacion
if (JOptionPane.showConfirmDialog(null,
"desea salir de la aplicacion?", "aviso",
JOptionPane.YES_NO_OPTION) == 0)
System.exit(0);
// igual pero con un simbolo de informacion
JOptionPane.showConfirmDialog(this,
"Desea continuar?", "informacion",
JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.INFORMATION_MESSAGE);
// para pedir un dato
String nombre =
JOptionPane.showInputDialog("Su nombre:");
// elegir un dato de una lista
Object[] valores = { "Norte","Sur", "Este","Oeste" };
Object selectedValue =
JOptionPane.showInputDialog(
null, // ventana madre
"Elige una direccion", // mensaje
"Direcciones", // titulo
JOptionPane.INFORMATION_MESSAGE, // tipo mensaje
null, // icono
valores, // valores
valores[0] // valor marcado inicialmente
);
// añadimos el "listener" para cerrar la ventana
addWindowListener(new ParaAcabar());
}
}
// clase para cerrar la ventana
class ParaAcabar extends WindowAdapter {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
Este programa muestra las siguientes ventanas de diálogo (consecutivamente, cada una tras
cerrar la anterior):
2004-2006 Rafael Caballero