applets java

23
Applets Java Autor: Daniel Rodríguez Herrera Introducción o Appletviewer o Programación orientada a eventos Introducción ES NECESARIO SABER JAVA Un applet es una pequeña aplicación accesible en un servidor Internet, que se transporta por la red, se instala automáticamente y se ejecuta in situ como parte de un documento web (definición de Patrick Naughton). Dado que Java es multiplataforma y los applets son soportados por ambos navegadores, su uso se ha popularizado bastante. Los applets tienen, sin embargo, un problema que impide que se utilicen más habitualmente. Este problema consiste en que, al igual que sucede con las imágenes, cuando colocamos un applet en una página web debemos definir un rectángulo de un tamaño determinado donde permanecerá el mismo, no pudiendo actuar fuera de sus márgenes. Appletviewer Podemos utilizar un navegador web como Explorer, Netscape o HotJava para ver nuestros applets, especialmente cuando los queremos incluir dentro de una página web ya construida. Sin embargo, mientras programemos el applet, será recomendable utilizar el programa que viene incluido en el JDK para probarlos. El appletviewer (nombre francamente explicativo) recibe como parámetro una página HTML y nos muestra el applet incluido en la misma en acción. Para utilizarlo, por lo tanto, debemos saber como incluir applets en una página HTML. El applet que desarrollaremos en el siguiente capítulo utiliza el siguiente código: AdiosMundo.html <HTML> <BODY> <APPLET CODE="AdiosMundo.class" WIDTH="200" HEIGHT="70"> </APPLET> </BODY> </HTML> Aparte de las etiquetas que marcan el comienzo y el fin del documento HTML y del cuerpo del mismo vemos la etiqueta APPLET, que es la encargada de llamar a estas pequeñas aplicaciones. Vemos que el parámetro CODE define la clase resultante de compilar el applet y que los parámetros WIDTH y HEIGHT definen el tamaño del rectángulo donde se va a meter el mismo. Si guardamos el archivo anterior como AdiosMundo.html, para ver el applet deberíamos ejecutar: appletviewer AdiosMundo.html

Upload: dashin1

Post on 30-Jun-2015

877 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: Applets Java

Applets Java Autor: Daniel Rodríguez Herrera

Introducción o Appletviewer o Programación orientada a eventos

Introducción

ES NECESARIO SABER JAVA

Un applet es una pequeña aplicación accesible en un servidor Internet, que se transporta por la red, se instala automáticamente y se ejecuta in situ como parte de un documento web (definición de Patrick Naughton). Dado que Java es multiplataforma y los applets son soportados por ambos navegadores, su uso se ha popularizado bastante.

Los applets tienen, sin embargo, un problema que impide que se utilicen más habitualmente. Este problema consiste en que, al igual que sucede con las imágenes, cuando colocamos un applet en una página web debemos definir un rectángulo de un tamaño determinado donde permanecerá el mismo, no pudiendo actuar fuera de sus márgenes.

Appletviewer

Podemos utilizar un navegador web como Explorer, Netscape o HotJava para ver nuestros applets, especialmente cuando los queremos incluir dentro de una página web ya construida. Sin embargo, mientras programemos el applet, será recomendable utilizar el programa que viene incluido en el JDK para probarlos. El appletviewer (nombre francamente explicativo) recibe como parámetro una página HTML y nos muestra el applet incluido en la misma en acción.

Para utilizarlo, por lo tanto, debemos saber como incluir applets en una página HTML. El applet que desarrollaremos en el siguiente capítulo utiliza el siguiente código:

AdiosMundo.html

<HTML>

<BODY>

<APPLET CODE="AdiosMundo.class" WIDTH="200"

HEIGHT="70">

</APPLET>

</BODY>

</HTML>

Aparte de las etiquetas que marcan el comienzo y el fin del documento HTML y del cuerpo del mismo vemos

la etiqueta APPLET, que es la encargada de llamar a estas pequeñas aplicaciones. Vemos que el

parámetro CODE define la clase resultante de compilar el applet y que los parámetros WIDTH y

HEIGHT definen el tamaño del rectángulo donde se va a meter el mismo.

Si guardamos el archivo anterior como AdiosMundo.html, para ver el applet deberíamos ejecutar:

appletviewer AdiosMundo.html

Page 2: Applets Java

Programación orientada a eventos

Si ya conoces Java, sin duda sabes de qué va eso de programación orientada a objetos. Sin embargo, y partir de ahora, deberemos comprender también en qué consiste el paradigma de programación orientada a eventos, pues la programación de applets responde también a dicho paradigma.

Cuando creamos un programa tradicional, de esos que se ejecutan desde la línea de comandos, el programa asume que es lo único que se está ejecutando y que no tiene porqué interactuar con un entorno más grande. De modo que empieza a ejecutarse y termina, pudiendo ver el programador el hilo de ejecución que va a seguir sin ningún problema. En el caso particular de Java, la aplicació n comienza cuando empieza el código

del método main y termina cuando llegamos al final de dicho método.

En cambio, si situamos un programa dentro de un entorno mayor, como puede ser una página web o un entorno multitarea como Windows o X-Windows lo que sucede es que el que se encarga de ejecutar las aplicaciones es dicho entorno. Y dado que son entornos donde pasan más cosas que la ejecución de nuestro programa, es necesario que éste no se ejecute de principio a fin, chupando toda la capacidad de proceso de ordenador.

Es entonces cuando entra en cancha este paradigma. La aplicación no se ejecuta de principio a fin, sino que lo hace en respuesta a mensajes que le manda el entorno en el que se ejecuta. Estos mensajes se envían cuando suceden eventos que el entorno piensa que afectan a la aplicación. Por ejemplo, cuando el ratón pasa por encima de la misma, cuando hay que redibujarla porque hemos cerrado una ventana que tenía encima, etc..

Los applets funcionan de esa manera. Disponen de muchos métodos que podemos sobreescribir y que se ejecutan al crearse el applet, al dejar de estar visible, cuando vuelve a estarlo, cuando el ratón pasa por encima suyo, cuando hay que redibujarlo, etc..

Nuestro primer applet

Nuestro primer applet

Vamos a crear nuestro primer applet, casi equivalente al típico "Hola, mundo" de toda la vida:

AdiosMundo.java

/**

* Applet AdiosMundo

*

* <APPLET CODE="AdiosMundo.class" WIDTH="200"

HEIGHT="70"></APPLET>

*/

import java.applet.Applet;

import java.awt.*;

public class AdiosMundo extends Applet {

public void paint(Graphics g) {

g.drawString("Adios, mundo cruel",20,20);

}

Page 3: Applets Java

}

Lo grabamos cono AdiosMundo.java y ejecutamos el appletviewer con el siguiente

comando:

appletviewer AdiosMundo.java

Esto parece contradecirse con lo explicado en el tema anterior. ¿No teníamos que llamar a una página HTML

que tuviera la etiqueta APPLET correspondiente? Bueno, sí. Lo que sucede es que appletviewer ignora

cualquier cosa que no sea una etiqueta APPLET, de modo que podemos incluirla en un comentario en

nuestro código fuente y así nos ahorramos tener que escribir una página HTML por cada ejemplo que veamos. Vamos ahora a examinar el código paso a paso:

import java.applet.Applet;

import java.awt.*;

En todos nuestro applets deberemos, como mínimo, incluir estas dos sentencias de importación. En la primera

importamos la clase Applet, de la cual derivaremos nuestros applets. La segunda permite importar las

clases de la librería AWT, que nos permitirán dibujar en el rectángulo asignado al applet.

public class AdiosMundo extends Applet {

}

Nuestros applet siempre van a ser clases derivadas de Applet, pues en esta clase y en sus clases padre

se definen los métodos que deberemos sobreescribir para que nuestros applets respondan a los eventos generados desde el navegador.

public void paint(Graphics g) {

}

Este es el método que debemos sobreescribir para dibujar en el rectángulo asignado a nuestro applet. Recibe

un parámetro que es una referencia a una instancia de tipo Graphics. Esta clase permite definir lo que

se suele denominar lienzo (o Canvas). El lienzo es precisamente ese rectángulo del que estamos hablando todo el rato.

g.drawString("Adios, mundo cruel",20,20);

La clase Graphics dispone de muchos métodos para dibujar en el lienzo. Éste, concretamente, nos permite dibujar un texto en la posición que queramos. En este caso el texto se pintará 20 pixels a la derecha del borde izquierdo de la pantalla y otros 20 más abajo del borde de arriba.

Ciclo de vida de un applet

Ciclo de vida de un applet

Como hemos visto, un applet se ejecuta en una página web y ese entorno en el que está va a determinar el

ciclo de vida del mismo. La clase Applet dispone de varios métodos sin código dentro a los que llama en

Page 4: Applets Java

diversas fases de su ciclo de vida (al crearse el applet, al redibujarse, al destruirse...). Si deseamos que nuestro applet haga cosas especiales en esos momentos deberemos sobreescribir esos métodos. Son éstos:

void init()

Este método se llama al crearse el applet y sólo se ejecuta esa vez. Se suele utilizar para inicializar variables globales.

void start()

Se llama cuando hay que activar el applet. Esto sucede cuando el applet se ve en la pantalla. Se suele utilizar para comenzar las actividades de applet, ya que en general éste debe estar visible en la pantalla para poder realizar su función.

void stop()

Es el inverso del anterior. Es llamado cuando el applet deja de estar visible. Se suele utilizar para

interrumpir las actividades activadas en start(). void destroy()

Método llamado al destruirse el applet. Normalmente no se suele sobreescribir, ya que la destrucción del applet conlleva la destrucción de todo lo que se ha creado en él. Puede ser útil para mostrar una ventana de confirmación que pregunte al usuario si de verdad debe cargárselo.

void repaint()

Este método no debería ser sobrecargado y es llamado cuando se necesita redibujar el applet.

Podemos llamarlo nosotros desde nuestro código. Llama a update(Graphics). void update(Graphics)

Llamado por repaint() cuando se necesita actualizar el applet. Su implementación borra el

rectángulo y llama a paint() para volver a pintarlo.

void paint(Graphics)

Método en el que se dibuja el applet y el cual deberemos sobreescribir para poder dibujar lo que nosotros deseemos..

void print(Graphics)

Equivalente a paint() pero es llamado cuando se va a imprimir el contenido del applet.

El siguiente ejemplo conviene observarlo desde un navegador e ir viendo los distintos mensajes que nos muestra el applet, para comprender cuando son llamados los métodos:

CicloDeVida.java /**

* Applet CicloDeVida

*

* <APPLET CODE="CicloDeVida.class" WIDTH="100" HEIGHT="400"></APPLET>

*/

import java.applet.Applet;

import java.awt.Graphics;

public class CicloDeVida extends Applet {

String mensajes;

public void init() {

mensajes = "Inicializando. ";

}

public void start() {

escribirMensaje("Método start. ");

}

public void stop() {

escribirMensaje("Método stop. ");

}

public void destroy() {

escribirMensaje("Destruyendo Applet. ");

}

void escribirMensaje(String nuevoMensaje) {

mensajes += nuevoMensaje;

repaint();

}

public void paint(Graphics g) {

g.drawString(mensajes, 5, 15);

}

Page 5: Applets Java

}

Etiqueta APPLET o Paso de parámetros

Etiqueta APPLET

La etiqueta APPLET presenta varios parámetros, de los cuales sólo es obligatorio poner los ya

comentados CODE, WIDTH y HEIGHT. Son los siguientes:

CODE

Nombre completo (incluyendo extensión) del fichero que contiene el applet. WIDTH

Anchura del rectángulo donde se ejecutará el applet. HEIGHT

Altura del rectángulo donde se ejecutará el applet. CODEBASE

Dirección donde está el fichero .class que contiene al applet. Es necesario ponerlo cuando el applet

se encuentra en un directorio distinto al de la página desde la que se le llama, ya que CODE no

puede contener directorios, sólo el nombre del fichero. ALT

Algunos navegadores comprenden la etiqueta APPLET pero no pueden mostrar applets. Esto es

debido a no tener instalada la máquina virtual Java o a que son navegadores en modo texto. En ese caso mostrarán el contenido de este parámetro en lugar del applet.

Hay alguno más, pero de poca importancia.

Paso de parámetros

Entre <APPLET> y </APPLET> podremos colocar etiquetas PARAM que nos permitirán pasar

parámetros al applet. Tienen dos atributos:

VALUE

Nombre del parámetro. NAME

Valor del parámetro.

Podemos obtener esos valores por medio del método getParameter(String), como vemos

en el siguiente ejemplo:

MostrarMensaje.java

/**

* Applet MostrarMensaje

*

* <APPLET CODE="MostrarMensaje.class" WIDTH="200"

HEIGHT="70">

* <PARAM NAME="Mensaje" VALUE="Mi mensaje propio">

* </APPLET>

Page 6: Applets Java

*/

import java.applet.Applet;

import java.awt.*;

public class MostrarMensaje extends Applet {

String mensaje;

public void init() {

mensaje = getParameter("Mensaje");

}

public void paint(Graphics g) {

g.drawString(mensaje,20,20);

}

}

Hay que destacar que Java no distingue entre mayúsculas y minúsculas en cuanto al nombre de los parámetros.

En muchos casos, el usuario puede que no incluya parámetros que consideramos necesarios o que escriba

mal el nombre de un parámetro. En ese caso, la llamada a getParameter() nos devolverá

null. Debemos tener cuidado con esto, ya que nos pueden saltar excepciones por esta clase de cosas.

Así pues, el código correcto de init() será:

public void init() {

mensaje = getParameter("Mensaje");

if (mensaje==null)

mensaje = "Mensaje por defecto";

}

De este modo, si nos equivocamos en la etiqueta PARAM, nos mostrará un mensaje y no lanzará ninguna

excepción.

Clase Graphics o Métodos de dibujo o Clase Color o Manejo de imágenes

Clase Graphics

La clase Graphics dispone de más métodos aparte de drawString, que nos permitirán dibujar figuras

e imágenes.

Métodos de dibujo

Mientras no se especifique, consideraremos que todos los parámetros son enteros:

Page 7: Applets Java

drawString(String texto,x,y)

Escribe un texto a partir de las coordenadas (x,y). drawLine(x1,y1,x2,y2)

Dibuja una línea entre las coordenadas (x1,y1) y (x2,y2). drawRect(x,y,ancho,alto) fillRect(x,y,ancho,alto) clearRect(x,y,ancho.alto)

Son tres métodos encargados de dibujar, rellenar y limpiar, respectivamente, un rectángulo cuya esquina superior izquierda está en las coordenadas (x,y) y tienen el ancho y alto especificados.

drawRoundRect(x,y,ancho,alto,anchoArco,altoArco) fillRoundRect(x,y,ancho,alto,anchoArco,altoArco)

Equivalentes a los anteriores, pero con las esquinas redondeadas. La forma y tamaño de dichas esquinas viene dada por los dos últimos parámetros.

draw3DRect(x,y,ancho,alto,boolean elevado) fill3DRect(x,y,ancho,alto,boolean elevado)

Equivalentes a los primeros, pero dibujan un borde para dar la sensación de que está elevado o hundido (dependiendo del valor del último parámetro).

drawOval(x,y,ancho,alto) fillOval(x,y,ancho,alto)

Dibujan una elipse con esquina izquierda superior en (x,y) y el ancho y alto especificados. Si son iguales dibujará un círculo.

drawArc(x,y,ancho,alto,anguloInicio,anguloArco) fillArc(x,y,ancho,alto,anguloInicio,anguloArco)

Dibuja una arco cuyo primer vértice está en (x,y) y el segundo en (x+ancho,y+alto). La forma del mismo vendrá dado por los dos últimos parámetros.

drawPolygon(int[] coordenadasX,int[] coordenadasY,numCoordenadas) fillPolygon(int[] coordenadasX,int[] coordenadasY,numCoordenadas)

Dibuja un polígono cerrado del número de puntos especificado en el último parámetro. copyArea(xOrigen,yOrigen,ancho,alto,xDest,yDest)

Copia el área cuya esquina superior izquierda está en (xOrigen,yOrigen) y de ancho y alto especificados a la zona que comienza en (xDest, yDest).

Por ejemplo, podemos dibujar lo siguiente:

Figurines.java

/**

* Applet Figurines

*

* <APPLET CODE="Figurines.class" WIDTH="200"

HEIGHT="70"></APPLET>

*/

import java.applet.Applet;

import java.awt.*;

public class Figurines extends Applet {

public void paint(Graphics g) {

g.drawString("Adios, mundo cruel",20,20);

g.fillRoundRect(10,30,50,20,10,10);

g.draw3DRect(100,30,50,20,true);

}

}

Page 8: Applets Java

Clase Color

Ahora ya sabemos como dibujar, sin embargo todo nos sale en un aburrido blanco y negro... Graphics

almacena internamente el color con el que pinta todo, que por defecto es negro. Para poder cambiar dicho

color deberemos utilizar el método setColor(), que recibe un único parámetro de tipo Color.

La clase Color dispone de varias propiedades estáticas que contienen los colores más comunes; son

Color.black (negro), Color.blue (añil), Color.cyan (azul),

Color.darkGray (gris claro), Color.gray (gris), Color.green (verde),

Color.lightGray (verde claro), Color.magenta (magenta), Color.orange

(naranja), Color.pink (rosa), Color.red (rojo), Color.white (blanco) y

Color.yellow (amarillo). Pero también se pueden crear instancias de color por medio de

constructores para definir colores menos comunes. Por ejemplo:

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

El color creado tendrá las cantidades de rojo, verde y azul indicadas, las cuales deberán estar en un rango que va de 0 a 255.

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

Idéntico al anterior, pero añade un canal alfa que indica el grado de transparencia. Sólo funciona con el JDK 1.2.

Cambiando el ejemplo anterior:

FigurinesColor.java

/**

* Applet FigurinesColor

*

* <APPLET CODE="FigurinesColor.class" WIDTH="200"

HEIGHT="70"></APPLET>

*/

import java.applet.Applet;

import java.awt.*;

public class FigurinesColor extends Applet {

public void paint(Graphics g) {

g.drawString("Adios, mundo cruel",20,20);

g.setColor(Color.green);

g.fillRoundRect(10,30,50,20,10,10);

g.setColor(new Color(30,40,50,100));

g.fill3DRect(50,40,50,20,true);

}

}

Manejo de imágenes

Page 9: Applets Java

Aún cuando podemos hacer cosas chulas con figuras, no estaría de más poder hacer cosas con imágenes, que son bastante más espectaculares. Para hacerlo deberemos utilizaremos el siguiente método:

drawImage( Image img,int x,int y,ImageObserver

observador )

Vemos que necesitamos un objeto Image y otro ImageObserver y de esas cosas no sabemos

todavía... No vamos a ver estos objetos muy a fondo. ImageObserver es un interfaz (que un

antepasado de Applet implementa) que nos ofrece información sobre la imagen según la imagen se

carga de la red. Por otro lado, Image es un objeto que representa a la imagen. Normalmente crearemos

un objeto Image por medio del método de Applet getImage():

Image img = getImage(URL base, String fichero)

Asigna la imagen contenida en la URL donde se encuentre el fichero que contiene la imagen que queremos presentar y el nombre de ese fichero.

Normalmente obtendremos esa dirección a partir de la página donde esté la página HTML o nuestro applet.

Para averiguarlo disponemos de dos métodos en la clase Applet:

URL getDocumentBase()

Devuelve la URL donde está la página HTML (excluyendo el nombre del fichero). URL getCodeBase()

Devuelve la URL donde está el applet (excluyendo el nombre del fichero).

Si deseamos obtener una URL distinta deberemos importar esa clase (java.net.URL) y crear uno

pasándole una cadena como parámetro al constructor conteniendo la URL.

Normalmente, se realiza el getImage() en el método init() del applet, ya que en el momento

en que ejecutemos este método comenzará la carga de imágenes desde Internet y eso conviene hacerlo

cuanto antes. Para mostrar la imagen se utiliza el método paint(), al igual que hemos hecho para

pintar cosas. Por ejemplo, suponiendo que tengamos un fichero llamado home.jpg:

Grafico.java

/**

* Applet Grafico

*

* <APPLET CODE="Grafico.class" WIDTH="200"

HEIGHT="70"></APPLET>

*/

import java.applet.Applet;

import java.awt.*;

public class Grafico extends Applet {

Image img;

public void paint(Graphics g) {

img = getImage(getDocumentBase(), "home.jpg");

Page 10: Applets Java

}

public void paint(Graphics g) {

g.drawImage(img,x,y,this);

}

}

Ejecución multihilo en applets

Ejecución multihilo en applets

Hasta ahora sólo disponíamos de un hilo de ejecución. Es decir, en nuestros programas sólo se ejecuta una cosa al tiempo. Si deseamos que se ejecuten varias cosas a la vez o simplemente deseamos disponer de una manera precisa de controlar la ejecución de parte de nuestro programa dependiendo del tiempo, necesitaremos que nuestro applet realice una ejecución multihilo.

El concepto de multitarea es diferente al de multihilo. El primero se suele aplicar a la ejecución concurrente de programas distintos, ya que para que exista multitarea se exige que cada proceso ejecutándose disponga de su propio espacio en la memoria. En el segundo caso, en cambio, todos los hilos que se ejecutan concurrentemente disponen del mismo espacio de memoria.

Pero no vamos a escribir un tratado filosófico sobre las diversas formas de programación concurrente. Lo mejor que podemos hacer es explicarlo sobre un ejemplo. El ejemplo siguiente es una modificación del applet

MostrarMensaje, realizado anteriormente, que realiza un scroll lateral del texto, que aparece por la

derecha y desaparece por la izquierda. El código nuevo que concierne a la ejecución multihilo está en negrita para facilitar su identificación:

Rotacion.java

/**

* Applet MostrarCadena

*

* <APPLET CODE="MostrarCadena.class" WIDTH="200"

HEIGHT="70">

* <PARAM NAME="Cadena" VALUE="Esto sí que es

chulo">

* </APPLET>

*/

import java.applet.Applet;

import java.awt.*;

public class MostrarCadena extends Applet implements

Runnable {

String mensaje;

int lugar;

Thread hilo = null;

Page 11: Applets Java

public void init() {

mensaje = getParameter("cadena");

if (mensaje==null)

mensaje = "Mensaje por defecto";

lugar = getBounds().width;

}

public void start() {

if (hilo==null) {

hilo = new Thread(this);

hilo.start();

}

}

public void stop() {

hilo = null;

}

public void paint(Graphics g) {

g.drawString(mensaje,lugar,20);

}

public void run() {

while (hilo!=null && hilo.isAlive()) {

lugar -= 1;

repaint();

try {

hilo.sleep(10);

}

catch (InterruptedException e) {} // No hacemos

nada

}

}

}

Lo primero es asegurarnos que nuestro applet implementa el interfaz Runnable, necesario para el

soporte de threads, o hilos de ejecución. Después declaramos un objeto de tipo Thread, es decir, hilo, y

lo igualamos a null. En el método start(), que es donde debe "estart" todo el código de

inicialización, creamos el hilo y lo arrancamos llamando a su método start(). En stop(), por el

contrario, lo paramos.

El método run() es nuevo y es consecuencia de la implementación del interfaz Runnable. Cuando

creamos un hilo de ejecución, como hemos hecho en start(), el hilo recién creado siempre comienza

su vida útil ejecutando el método run(). Así pues, aquí estará el código del hilo. Comenzamos

preguntando si existe nuestro hilo (hilo!=null) y si está ejecutandose (isAlive).

Page 12: Applets Java

Luego mueve el texto un poco a la izquierda, repinta, y se obliga a sí mismo a dejar de ejecutarse durante 10

milisegundos por medio del método sleep(). Transcurrido ese tiempo seguirá su ejecución por el mismo

sitio donde la dejó (de ahí que sea necesario el while).

Indicar por último que es obligatorio capturar la excepción InterruptedException para poder

llamar al método sleep(). En caso contrario el compilador se queja. Así pues, lo hacemos, aunque no

especifiquemos ningún código en caso de que se lance dicha excepción. Esto ocurrirá en casos muy excepcionales, por lo que no debemos preocuparnos.

Técnica Double-buffering

Técnica Double-buffering

Ejecutando el ejemplo del capítulo anterior, podemos observar un parpadeo mientras el texto avanza hacia la izquierda. Esto es debido al modo que tiene Java de actualizar la imagen que vemos del applet.

Cuando llamamos al método repaint(), éste se encarga de llamar a update(), el cual borra lo

que haya en el applet y llama a paint() para pintarlo de nuevo. Y todo eso lo contemplan nuestros ojos.

El parpadeo es debido a que nuestro ojo se da cuenta de que hemos borrado la pantalla y que tardamos cierto tiempo en escribir de nuevo el texto.

Para remediarlo existe un técnica llamada double-buffering. Esta técnica no es exclusiva de Java, pues por ejemplo muchos de los juegos que utilizamos la implementan, o incluso utilicen técnicas más complicadas. Este método consiste en construir una pantalla virtual, que no vemos pero que existe en la memoria del ordenador, y pintar en ella lo que necesitemos mostrar para volcarla a la pantalla real cuando lo necesitemos.

Eso elimina nuestros dos problemas. Primero, no borramos nunca la pantalla, sino que la sustituimos, por lo que la retina no aprecia que se quede en blanco en ningún momento. Segundo, el volcado es un proceso muy rápido, por lo que no se pueden apreciar que la pantalla virtual se ha volcado sólo un cachito pero otro no como sucedía cuando dibujábamos directamente.

Para implementar esta técnica, deberemos tener en cuenta que Graphics es una clase abstracta, por lo

que no podemos utilizarla para crear esa pantalla virtual. En cambio, utilizaremos Image, que dispone de

un método que nos será muy útil en este caso:

Graphics img.getGraphics()

Este método creará un lienzo a partir de una imagen, con las mismas dimensiones que ésta.

También utilizaremos el método de Applet llamado createImage(anchura,

altura) que crea una imagen en blanco del tamaño especificado. Así pues, vamos a modificar nuestro

famoso ejemplo, ennegreciendo de nuevo el código nuevo que interviene en la implementación en Java de la técnica double-buffering:

MostrarCadena.java

/**

* Applet MostrarCadena

*

* <APPLET CODE="MostrarCadena.class" WIDTH="200"

HEIGHT="70">

Page 13: Applets Java

* <PARAM NAME="Cadena" VALUE="Esto sí que es

chulo">

* </APPLET>

*/

import java.applet.Applet;

import java.awt.*;

public class MostrarCadena extends Applet implements

Runnable {

String mensaje;

int lugar, ancho, alto;

Thread hilo = null;

Image buffer;

Graphics pantallaVirtual;

public void init() {

mensaje = getParameter("cadena");

if (mensaje==null)

mensaje = "Mensaje por defecto";

ancho = getBounds().width;

alto = getBounds().height;

lugar = ancho;

buffer = createImage(ancho, alto);

pantallaVirtual = buffer.getGraphics();

}

public void start() {

if (hilo==null) {

hilo = new Thread(this);

hilo.start();

}

}

public void stop() {

hilo = null;

}

public void paint(Graphics g) {

g.drawString(mensaje,lugar,20);

}

public void update(Graphics g) {

Color colorTemporal = pantallaVirtual.getColor();

pantallaVirtual.setColor(Color.white);

pantallaVirtual.fillRect(0, 0, ancho, alto);

pantallaVirtual.setColor(colorTemporal);

Page 14: Applets Java

paint(pantallaVirtual);

g.drawImage(buffer, 0, 0, this);

}

public void run() {

while (hilo!=null && hilo.isAlive()) {

lugar -= 1;

repaint();

try {

hilo.sleep(10);

}

catch (InterruptedException e) { // No hacemos

nada

}

}

}

}

Inicializamos los dos nuevos objetos necesarios para implementar esta técnica en el método init()

utilizando como tamaño de la imagen y su lienzo asociado el del applet. Este tamaño lo averiguamos por

medio de una llamada a getBounds().

El proceso de implementar la técnica se realiza en la sobreescritura del método update(). Este método

recibe como parámetro el lienzo correspondiente al rectángulo que ocupa el applet en la pantalla. Sin embargo, lo que hace es limpiar el lienzo de la pantalla virtual y llama a paint utilizando como parámetro este

último lienzo, por lo que paint() dibuja en la pantalla virtual. Por último, vuelca el buffer en la pantalla

real.

Esto último es posible debido a que buffer y pantallaVirtual son referencias que apuntan a objetos que en realidad representan lo mismo. De modo que todo lo que hagamos al lienzo pantallaVirtual se ve reflejado en la imagen buffer y viceversa.

Eventos

Eventos

La interacción con el usuario se obtiene en Java por medio de eventos, como ya fue explicado. Cuando sucede un evento que afecta al applet, la máquina virtual de Java ejecuta un método que se llama controlador de eventos. En principio esos métodos no tienen nada, por lo que deberemos sobreescribirlos en función de nuestras necesidades. Esos métodos son:

boolean mouseDown(Event, int, int)

Llamado cuando pulsamos un botón del ratón; los parámetros segundo y tercero contienen la posición del ratón cuando ocurrió el evento, mientras que el primero en un objeto que contiene información adicional sobre el mismo.

boolean mouseUp(Event, int, int)

Llamado cuando soltamos el botón del ratón después de haberlo pulsado. boolean mouseMove (Event, int, int)

Llamado cuando movemos el ratón.

Page 15: Applets Java

boolean mouseDrag (Event, int, int)

Llamado cuando movemos el ratón con un botón pulsado. boolean mouseEnter (Event, int, int)

Llamado cuando el ratón entra en el applet. boolean mouseExit (Event, int, int)

Llamado cuando el ratón abandona el applet. boolean keyDown(Event,int)

Llamado cuando se pulsa una tecla. El argumento entero indica cuál. boolean keyUp(Event, int)

Llamado cuando se suelta una tecla.

Como ejemplo, podemos hacer un ojo que sigue al ratón:

Ojo.java

/**

* Applet Ojo

*

* <APPLET CODE="Ojo.class" WIDTH="300" HEIGHT="300">

* <PARAM NAME="Cadena" VALUE="Esto sí que es

chulo">

* </APPLET>

*/

import java.applet.Applet;

import java.awt.*;

public class Ojo extends Applet {

int ancho, alto, anchoOjo, altoOjo, anchoPupila,

altoPupila;

int xOjo, yOjo, xPupila, yPupila, xActual, yActual;

Image buffer;

Graphics pantallaVirtual;

public void init() {

ancho = getBounds().width;

alto = getBounds().height;

anchoOjo = ancho / 2;

altoOjo = alto / 2;

anchoPupila = anchoOjo / 2;

altoPupila = altoOjo / 2;

xOjo = anchoOjo - anchoPupila;

yOjo = altoOjo - altoPupila;

xPupila = xOjo + anchoPupila/2;

yPupila = yOjo + altoPupila/2;

xActual = xPupila;

yActual = yPupila;

buffer = createImage(ancho, alto);

Page 16: Applets Java

pantallaVirtual = buffer.getGraphics();

}

public void paint(Graphics g) {

g.setColor(Color.yellow);

g.fillOval(xOjo, yOjo, anchoOjo, altoOjo);

g.setColor(Color.black);

g.fillOval(xActual, yActual, anchoPupila,

altoPupila);

}

public void update(Graphics g) {

Color colorTemporal = pantallaVirtual.getColor();

pantallaVirtual.setColor(Color.white);

pantallaVirtual.fillRect(0, 0, ancho, alto);

pantallaVirtual.setColor(colorTemporal);

paint(pantallaVirtual);

g.drawImage(buffer, 0, 0, this);

}

public boolean mouseMove(Event evt, int x, int y) {

xActual = (xPupila*21 + x*8)/32;

yActual = (yPupila*21 + y*8)/32;

repaint();

return true;

}

}

El controlador de evento mouseMove se ejecuta cuando el ratón se mueve por encima del applet. Es en

ese momento cuando se modifica la situación de la pupila del ojo, siguiendo al puntero del ratón. La "formula", la verdad, está hallada a ojo, cosa que me pareció muy natural en este caso. Además, hacerlo bien requeriría que nos metieramos en asuntos trigonométricos, y son asuntos estos muy peliagudos.

Clase MediaTracker

Clase MediaTracker

Para poder controlar mejor el viaje que hacen por la red los archivos gráficos, deberemos recurrir a la clase

MediaTracker. Esta clase nos permite saber cuando se han descargado los gráficos y si lo han

hecho bien o con errores.

Primero crearemos un objeto:

MediaTracker tracker = new MediaTracker(this);

Page 17: Applets Java

Este constructor toma como parámetro el componente donde se van a dibujar las imágenes. Puesto que un

applet es un componente, utilizaremos this como parámetro. Dispondremos entonces de los siguientes

métodos:

void tracker.addImage( Image img,int id )

Este es el método esencial, pues especifica que la imagen sea "espiada" con

MediaTracker. Le asigna un número de identificación, que puede ser compartido por varias

imágenes. boolean tracker.checkAll() boolean tracker.checkAll(boolean load)

Comprueba todas las imágenes, devolviendo false si aún no se han descargado y true en

caso contrario (incluso cuando se han descargado con fallos). Si aún no ha comenzado la descarga

de alguna imagen y ponemos load a true, comenzará a descargarlas en ese mismo instante.

boolean tracker.checkID(int id) boolean tracker.checkID(int id,boolean load)

Idéntico al anterior, pero comprueba sólo las imágenes cuyo identificador sea igual a id.

void tracker.waitForAll()

Obliga al hilo actual a esperar a que se carguen todas las imágenes. void tracker.waitForID(int id)

Obliga al hilo actual a esperar a que se carguen todas las imágenes del grupo id.

boolean tracker.isErrorAny()

Indica si se ha producido algún error en la descarga de alguna imagen. boolean tracker.isErrorID(int id)

Indica si se ha producido algún error en la descarga de alguna imagen.

Existen más, pero en general son otras formas de hacer lo mismo. Vamos a ver un ejemplo, una animación gráfica. Para ello cargaremos cada uno de los gráficos, esperaremos a que estén disponibles, y finalmente los mostraremos:

MostrarAnimacion.java

/**

* Applet MostrarAnimacion

*

* <APPLET CODE="MostrarAnimacion.class" WIDTH="56"

HEIGHT="60">

* </APPLET>

*/

import java.applet.Applet;

import java.awt.*;

public class MostrarAnimacion extends Applet

implements Runnable {

int imgActual = 0;

Thread hilo = null;

Image[] img;

MediaTracker tracker;

public void init() {

tracker = new MediaTracker(this);

Page 18: Applets Java

img = new Image[18];

for (int i=0; i<=17; i++) {

img[i] = getImage(getDocumentBase(), "tierra" +

(i+1) + ".gif");

tracker.addImage(img[i], 0);

}

}

public void start() {

if (hilo==null) {

hilo = new Thread(this);

hilo.start();

}

}

public void stop() {

hilo = null;

}

public void paint(Graphics g) {

if (checkAll())

g.drawImage(img[imgActual],0,0,this);

else {

g.drawString("Cargando",10,10);

g.drawString("gráficos",10,30);

}

}

public void run() {

try {

repaint();

tracker.waitForAll();

}

catch (InterruptedException e) {}

while (hilo!=null && hilo.isAlive()) {

imgActual++;

if (imgActual >= img.length) imgActual = 0;

repaint();

try {

hilo.sleep(50);

}

catch (InterruptedException e) {}

}

}

public void update(Graphics g) {

paint(g);

Page 19: Applets Java

}

}

Creamos un hilo de ejecución nuevo para que nuestra animación sea fluida y suavecita. El método run(),

no obstante, lo primero que hace es esperar hasta que se carguen las animaciones; paint() mientras

tanto escribirá el texto "Cargando gráficos". Una vez que se hayan terminado de cargar las imágenes, el hilo se encarga de mostrar un fotograma cada 50 milisegundos.

Sonido

Sonido

En Java existe una manera (tampoco muy precisa, pero mucho mejor que las que ofrece Javascript o HTML)

de hacer funcionar ficheros de sonido. Para ello utilizaremos el interfaz AudioClip:

AudioClip sonido = getAudioClip(getDocumentBase(),

"musica.au");

Con esto cargaremos el sonido que esté en el fichero "musica.au". Para hacer algo con él disponemos de tres métodos:

Sonido.play()

Toca el fichero, aunque sólo una vez. Sonido.loop()

Toca el fichero indefinidamente. Sonido.stop()

Para la reproducción del sonido.

Aquí no disponemos de un MediaTracker para comprobar si se ha terminado de cargar o no.

Afortunadamente, la variable sonido será igual a null hasta que finalice la carga del fichero. De

modo que estaremos todo el rato comprobando si esa variable tiene dicho valor, y cuando no sea así tocaremos un poco de música:

Suena.java

/**

* Applet Suena

*

* <APPLET CODE="Suena.class" WIDTH="56" HEIGHT="60">

* </APPLET>

*/

import java.applet.Applet;

import java.awt.*;

public class MostrarAnimacion extends Applet

implements Runnable {

Page 20: Applets Java

AudioClip sonido;

Thread hilo = null;

public void init() {

sonido = getAudioClip(getDocumentBase(),

"musica.au");

}

public void start() {

if (hilo==null) {

hilo = new Thread(this);

hilo.start();

}

}

public void stop() {

hilo = null;

}

public void run() {

while (hilo!=null && hilo.isAlive()) {

if (sonido != null) {

sonido.loop();

hilo = null;

}

try {

hilo.sleep(1);

}

catch (InterruptedException e) {}

}

}

}

Clase FontMetrics

Clase FontMetrics

Vamos a ver cómo averiguar datos sobre el tipo de letra que se está utilizando en nuestro applet, principalmente para poder situarlo dentro del applet con mayor precisión.

FontMetrics fm = getFontMetrics(getFont());

La clase FontMetrics aporta información sobre las dimensiones del tipo de letra. Dispone de

muchos métodos, pero normalmente usaremos sólo dos:

int fm.getHeight()

Page 21: Applets Java

Devuelve la altura en pixels de un carácter del tipo de letra actual. int fm.stringWidth(String)

Devuelve el ancho en pixels de una cadena escrito con el tipo de letra actual.

Nos aprovecharemos de estas cositas para hacer que nuestro applet con el texto desplazándose coloque el texto en el centro del applet y nos vuelva a mostrar el mismo por la derecha cuando salga por la izquierda:

MostrarCadena.java

/**

* Applet MostrarCadena

*

* <APPLET CODE="MostrarCadena.class" WIDTH="200"

HEIGHT="70">

* <PARAM NAME="Cadena" VALUE="Esto sí que es

chulo">

* </APPLET>

*/

import java.applet.Applet;

import java.awt.*;

public class MostrarCadena extends Applet implements

Runnable {

String mensaje;

int lugar, ancho, alto, anchoMensaje, ,altoMensaje;

Thread hilo = null;

Image buffer;

Graphics pantallaVirtual;

public void init() {

mensaje = getParameter("cadena");

if (mensaje==null)

mensaje = "Mensaje por defecto";

ancho = getBounds().width;

alto = getBounds().height;

lugar = ancho;

anchoMensaje =

getFontMetrics().stringWidth(mensaje);

altoMensaje =

(getFontMetrics().getHeight()+alto)/2;

buffer = createImage(ancho, alto);

pantallaVirtual = buffer.getGraphics();

}

public void start() {

if (hilo==null) {

Page 22: Applets Java

hilo = new Thread(this);

hilo.start();

}

}

public void stop() {

hilo = null;

}

public void paint(Graphics g) {

g.drawString(mensaje,lugar,altoMensaje);

}

public void update(Graphics g) {

Color colorTemporal = pantallaVirtual.getColor();

pantallaVirtual.setColor(Color.white);

pantallaVirtual.fillRect(0, 0, ancho, alto);

pantallaVirtual.setColor(colorTemporal);

paint(pantallaVirtual);

g.drawImage(buffer, 0, 0, this);

}

public void run() {

while (hilo.isAlive()) {

lugar --;

if (lugar < (-anchoMensaje))

lugar = ancho;

repaint();

try {

hilo.sleep(10);

}

catch (InterruptedException e) { // No hacemos

nada

}

}

}

}

Documentación

Documentación

En muchas ocasiones, se distribuyen los applets haciendo públicos sólo los ficheros .class. En ese caso, es muy posible que el usuario se encuentre con dichos ficheros sin tener una idea muy clara de la utilidad del applet o de sus parámetros (ni siquiera de qué parámetros son éstos). Para informar de ello al usuario disponemos de dos métodos que deberemos sobreescribir:

Page 23: Applets Java

String getAppletInfo()

Devuelve una cadena que identifique el applet. String[][] getParameterInfo()

Devuelve un array bidimensional, donde la primera dimensión es el número de parámetros y la segunda es 3. Cada parámetro dispone, por tanto, de tres cadenas para detallar su información: la primera indica el nombre del mismo, la segunda su rango de valores y la tercera su utilidad.

Como ejemplo, vamos a añadir estos dos métodos en nuestro applet MostrarCadena. Luego, desde el menú del appletviewer, elegiremos la opción Info para ver el resultado:

public String getAppletInfo() {

return "Applet MostrarCadena, por Daniel Rodriguez

Herrera";

}

public String[][] getParameterInfo() {

String[][] pInfo = return pInfo;

}