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