Applets Java


En esta página:

  • 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">
 *   <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.