Bueno, el problema que nos queda es el molesto "flicker", o sea la manera en que titila el dibujo cuando movemos el mouse. Esto es porque cada vez que se llama a paint(), el fondo se borra y se redibuja todo el canvas.
Básicamente, la manera de evitarlo es reescribiendo el método update(), que es el que borra el fondo antes de llamar a paint() para que no lo borre; otro método (que es el que vamos a usar) es dibujar
no sobre la pantalla sino sobre un "buffer" gráfico, y luego copiar ese buffer sobre la pantalla (lo que es mucho más eficiente que dibujar sobre la misma).
Para eso vamos a crear un par de objetos:
class miCanvas extends Canvas {
Vector v = new Vector();
Image imgBuff;
Graphics grafBuff;
.............................
Image es una clase abstracta, madre de todas las clases que representan imágenes gráficas. Graphics es también abstracta y nos permite obtener un contexto en el cual dibujar.
Lo que vamos a hacer es modificar nuestro método paint() para que simplemente llame a update(), y redefinir el método update():
public void paint(Graphics g) {
update(g);
}
El método update() es el que hará todo el trabajo y básicamente es como nuestro viejo paint() con algunos agregados:
public void update(Graphics g) {
int i;
Dimension d = size();
if (grafBuff null) {
imgBuff = createImage(d.width, d.height);
grafBuff = imgBuff.getGraphics();
}
grafBuff.setColor(getBackground());
grafBuff.fillRect(0, 0, d.width, d.height);
grafBuff.setColor(Color.red);
grafBuff.drawRect(0, 0, d.width-1, d.height-1);
grafBuff.setColor(Color.blue);
if (v.size() > 0) for (i=0; i<v.size(); i++) {
Rectangle box = cortarRect((Rectangle)v.elementAt(i), d);
grafBuff.drawRect(box.x, box.y, box.width-1, box.height-1);
}
g.drawImage(imgBuff, 0, 0, this);
}
En
negrita hemos indicado los agregados.
Si no está creado todavía (grafBuff
null), creamos nuestro buffer de dibujo. Para crear dicho buffer gráfico (de clase Graphics), primero creamos una imagen que en este caso tiene las mismas dimensiones que el canvas (d.width x d.height), y luego asignamos a grafBuff el contexto de dicha imagen mediante el método getGraphics(). Imagínense que con createImage(...) crean una "pantalla virtual", y getGraphics() nos da una forma de acceder a esa pantalla como si fuera real.
Utilizando dicho contexto, elegimos como color el mismo color de fondo del applet (getBackground()) y dibujamos un rectángulo lleno (fillRect(...)), borrando así cualquier cosa que hubiera estado dibujada.
En
itálica hemos indicado las modificaciones a nuestro método anterior. Simplemente, en lugar de usar el contexto de la pantalla (el parámetro g del método), dibujamos sobre nuestro contexto-pantalla virtual.
Finalmente, y para poder visualizar nuestro dibujo, usamos el método drawImage sobre el contexto de la pantalla real (g), que copia nuestro contexto imgBuff en las coordenadas (0,0) sobre la pantalla. Se hace también referencia al canvas (...this): el cuarto parámetro de drawImage es un objeto de clase ImageObserver, una interface que sirve para que el objeto dentro del cual se dibuja reciba mensajes asincrónicos que le indican cómo está siendo construida la imagen, y cuándo está lista.