0% encontró este documento útil (0 votos)
22 vistas

Conocer Java AWTprogramacion II

k

Cargado por

Kenneth Gaitán
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
22 vistas

Conocer Java AWTprogramacion II

k

Cargado por

Kenneth Gaitán
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 54

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.- Diálogos y mensajes

1.- Introducción

1.1 AWT y Swing


1.2 Un poco de filosofía
1.3 La jerarquía Component

1.1 AWT y Swing

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.

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.

1.2 Un poco de filosofía

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

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.

1.3 La jerarquía Component

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

Algunas observaciones sobre estos métodos:

1. La clase Dimension de AWT sirve para almacenar el ancho y el alto de un


componente. Sus métodos más importantes son double getWidth(), double
getHeight() y sus correspondientes set.
2. La clase Font de AWT representa los tipos de letra. Es una clase compleja que
no vamos a ver en profundidad. La forma más habitual de uso es como en este
ejemplo:

// Arial de 12 pts en negrita


Font fuenteNegrita = new Font("Arial",Font.BOLD,12);

Las constantes de formato son: Font.PLAIN, Font.BOLD y Font.ITALIC.


3. La clase Point de AWT se utiliza para representar las coordenadas de un punto
(x,y). Tiene una constructora Point(x,y) y métodos tales como int getX(), int
getY(), void setX(int x), void setY(int y) y void move(int x, int y).

El siguiente diagrama muestra esquemáticamente las clases derivadas de Component:


Aunque no vamos a estudiarlas todas, conviene saber para qué sirve cada una de ellas, y
referirnos a la ayuda de Java cuando sea necesario:
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
Campo de edición que puede utilizar el usuario para introducir
TextField
datos
Similar a TextField pero permite introducir texto que ocupe
TextArea
varias líneas

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" )

2.- Ventanas: la clase Frame

2.1 Abriendo las ventanas


2.2 Cerrando las ventanas
2.3 Ejemplo
2.4 Utilización de la herencia

2.1 Abriendo las ventanas

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.

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

Para crear e inicializar una ventana AWT (Frame) vamos a seguir los siguientes pasos:

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étodo
Toolkit.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.
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:

2.2 Cerrando las ventanas

Una ventana puede recibir los siguientes tipos de eventos:

 WINDOW_OPENED
 WINDOW_CLOSING
 WINDOW_CLOSED
 WINDOW_ICONIFIED
 WINDOW_DEICONIFIED
 WINDOW_ACTIVATED
 WINDOW_DEACTIVATED
 WINDOW_GAINED_FOCUS
 WINDOW_LOST_FOCUS
 WINDOW_STATE_CHANGED

Para tener acceso a ellos debemos:

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.
Los métodos son:

 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 {

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.

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);

2.3 Ejemplo

El siguiente programa reúne todos los conceptos anteriores:

Principal.java

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

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

Principal.java

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.- Componentes Básicos

3.1 Etiquetas: la clase Label


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

3.1 Etiquetas: la clase Label

La clase Label(etiqueta) se utiliza para mostrar Strings en un componente.

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.

3.2 Botones: la clase Button

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:

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

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

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:

1. 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.
2. Declarar un objeto del tipo anterior (normalmente en la constructora de
la ventana, a la vez que se crea el botón).
3. 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 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.

 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.*;

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:

1.

Definir un atributo en la clase escucha que contendrá una referencia al


componente externo deseado.
Este atributo se inicializará mediante la constructora.

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.

Escribir la clase escucha dentro de la clase Ventana.

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() {

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

Este componente se utiliza comúnmente para leer datos de teclado.

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:

PalabraClave.java

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

Es similar a TextField con la diferencia de que al presentarse en pantalla permite


introducir código que ocupa más de una línea.
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:
o SCROLLBARS_BOTH
o SCROLLBARS_HORIZONTAL_ONLY
o SCROLLBARS_NONE
o 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

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


4.2 Eventos de ratón

4.1 Eventos de teclado

Los 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:
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.
El interfaz KeyListener dispone de los siguientes métodos:

 void keyPressed(KeyEvent e): Tecla pulsada.


 void keyReleased(KeyEvent e): Se dejó de pulsar la tecla.
 void keyTyped(KeyEvent e): La combinación de las dos anteriores.

Por su parte, el parámetro de tipo KeyEvent contiene los siguientes métodos que nos
ayudan a identificar la tecla concreta:

 char getKeyChar(): Devuelve el carácter asociado a la tecla, si es una tecla


normal (imprimible). Las teclas especiales devuelven la constante
CHAR_UNDEFINED.
 boolean isActionKey(): Devuelve true si la tecla es una tecla especial o false si
es imprimible.
 int getKeyCode(): Devuelve una constante identificando a la tecla si es una tecla
especial. Algunas de estas constantes son:
VK_ACCEPT, VK_ALT, VK_ALT_GRAPH, VK_BACK_QUOTE,
VK_BACK_SLASH, VK_BACK_SPACE, VK_CANCEL, VK_CAPS_LOCK,
VK_CLEAR, VK_CLOSE_BRACKET, VK_CODE_INPUT, VK_COLON,
VK_COMMA, VK_COMPOSE, VK_CONTROL, VK_COPY, VK_CUT,
VK_DELETE, VK_DOWN, VK_END, VK_ENTER, VK_ESCAPE,
VK_EURO_SIGN, VK_F1, VK_F10, VK_F11, VK_F12, VK_F13, VK_F14,
VK_F15, VK_F16, VK_F17, VK_F18, VK_F19, VK_F2, VK_F20, VK_F21,
VK_F22, VK_F23, VK_F24, VK_F3, VK_F4, VK_F5, VK_F6, VK_F7,
VK_F8, VK_F9, VK_FINAL, VK_FIND, VK_HELP, VK_HOME,
VK_INSERT, VK_LEFT, VK_NUM_LOCK, VK_NUMPAD0,
VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4,
VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, VK_NUMPAD8,
VK_NUMPAD9, VK_O, VK_PAGE_DOWN, VK_PAGE_UP, VK_PASTE,
VK_PAUSE, VK_PRINTSCREEN, VK_RIGHT, VK_SCROLL_LOCK,
VK_SHIFT, VK_STOP, VK_TAB, VK_UNDEFINED, VK_UNDO, VK_UP.

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 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) { }


}

4.2 Eventos de ratón

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:

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

La clase MouseEvent tiene entre otros métodos:

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

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);

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

5.1 Introducción
5.2 Estilo FlowLayout
5.3 Estilo BorderLayout
5.4 Estilo GridLayout
5.5 Paneles

5.1 Introducción

El estilo (o diseño) de un contenedor indica cómo se dispondrán los componentes


básicos en él.
Se establece mediante el método void setLayout(LayoutManager l) de la clase
Container.
La clase LayoutManager es la clase de la que heredan todos los estilos (layouts). Cada
contenedor tiene un estilo por defecto. Por ejemplo, en el caso de Frame este es
BorderLayout, y en el de Panel FlowLayout.

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.

5.2 Estilo FlowLayout


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:
Constructoras
Tiene 3 constructoras:

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

Ejemplo: Añadimos 10 botones para ver como se colocan en la ventana con


FlowLayout

EstiloFlowLayout.java

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); }
}

El resultado es:
5.3 Estilo BorderLayout

Es el estilo por defecto de Frame.


El estilo BorderLayout divide el contenedor en 5 áreas: Norte, Sur, Este, Oeste y centro,
indicadas por las 5 constantes: BorderLayout.NORTH, BorderLayout.SOUTH,
BorderLayout.EAST, BorderLayout.WEST y BorderLayout.CENTER.
Cada componente puede ocupar un área únicamente; y a ser posible debe ocuparla por
entero. Si se añaden dos componentes a la misma área, sólo será visible el último de
ellos.
El área que ocupa el componente se indica al incorporarlo al contenedor con add. Si no
se indica nada se colocará en el centro.
Constructoras

 BorderLayout(): Constructora por defecto.


 BorderLayout(int sepHorizontal, int sepVertical): Incluye la separación
en pixels entre los componentes.

Ejemplo

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.

5.4 Estilo GridLayout

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.
Los componentes se van colocando en la siguiente posición libre, comenzando desde
arriba a la izquierda.
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

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:
5.5 Paneles

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.

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.

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:

Antes de escribir el programa pensamos en el diseño de la ventana:


Con este diseño podemos escribir el código:

Tablero.java

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

 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()

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

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.

 Cuando un objeto necesita repintarse, llama a su método public void


update(Graphics g).
 El comportamiento por defecto de update es:
o Borrar el componente.
o 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().

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

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

6.2 La clase Canvas

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

// clase para dibujar


public class Lienzo extends Canvas {
...
// aquí se incluirá el código para dibujar
public void paint(Graphics g) {
....
}
.....
}

Ventana.java

import java.awt.*;
import java.awt.event.*;

public class Ventana extends Frame {


......

public Ventana() {
....
....
Lienzo l = new Lienzo();

add(l);

.......
......
}
}
......

Principal.java

public class Principal {


public static void main(String[] args) {
new Ventana();
}
}
6.3 La clase Graphics

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

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.

Observación: Si el punto final es igual al inicial se


dibuja un punto. Esto es importante porque no existe
ningún método para dibujar puntos, por lo que lo normal es
utilizar drawLine(x,y,x,y).

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.

6.4 Mostrando imágenes

Para mostrar imágenes que están en disco en forma .gif o .jpg podemos seguir el
procedimiento siguiente:

1. Leer la imagen del fichero con el método


Toolkit.getDefaultToolkit().getImage(String nombre). En la que el nombre es el
nombre del fichero. Este método devuelve un valor de tipo Image, por lo que la
instrucción podría ser del estilo:

Image img = Toolkit.getDefaultToolkit().getImage("foto.gif");

2. La clase Image es la que se utiliza para representar imágenes genéricas en Java.


3. Utilizar el método showImage de Graphics. Este método esta sobrecargado tal y
como vimos en el punto anterior.

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 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();

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("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();
}
}

Principal.java

public class Principal {


public static void main(String[] args) {
new Ventana();
}
}

7.- Diálogos y Mensajes

8.1 La clase Dialog


8.2 La clase FileDialog
8.3 La clase JOptionPane

7.1 La clase Dialog

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:

 Diálogos modales: No se puede actuar sobre la aplicación hasta que no se haya


cerrado el diálogo. Son los más comunes.
 Diálogos no modales: No necesitan cerrarse para seguir trabajando sobre la
aplicación.

Dado que los diálogos son un tipo especial de ventanas, no tenemos que describir sus
métodos, tan sólo sus constructoras:
Constructoras

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

7.2 La clase FileDialog

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

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

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).
El siguiente ejemplo ilustra como se puede utilizar este diálogo para abrir un fichero:

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);
}
}

7.3 La clase JOptionPane

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.

Observación: Es posible (y bastante normal) mezclar en una misma aplicación


componentes awt con componentes swing.

Los principales métodos de esta clase son cuatro métodos estáticos:

 showConfirmDialog: Diálogo para pedir confirmación, como los típicos


diálogos con los botones si/no/cancelar.
 showInputDialog: Para pedir una entrada de datos al usuario.
 showMessageDialog: Información para el usuario, con un botón de aceptar.
 showOptionDialog: Combina las posibilidades de los tres anteriores.

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 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):
20

También podría gustarte