⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 java13.htm

📁 E-books about Java Programing in Spanish
💻 HTM
字号:
<HTML>
<HEAD>
<TITLE>Curso Java desde Cero</TITLE>

<META NAME="GENERATOR" CONTENT="Internet Assistant for Microsoft Word 2.0z">
</HEAD>
<BODY background=/iconos/1.gif  TEXT=000000 LINK=FF0000 VLINK=A62A2A>  
<H1>DibuJava II<BR>
</H1>
<P>
Vamos a retocar un poquito nuestro <FONT FACE="Arial">ejemplo15</FONT>
para que no se borren los rect&aacute;ngulos cuando queremos dibujar
uno nuevo. Aprenderemos algo sobre la clase <B>Vector</B>, perteneciente
al paquete java.util.
<H2>Vectores en acci&oacute;n</H2>
<P>
Los vectores nos permiten hacer arreglos de cualquier tipo de
objeto, y referirnos individualmente a cualquier elemento del
vector, aunque para utilizarlos (debido a que para java el vector
contiene objetos gen&eacute;ricos) tendremos que decirle qu&eacute;
clase de objeto es mediante un &quot;cast&quot;. Vamos a ver c&oacute;mo
quedan nuestras clases <FONT FACE="Arial">Ejemplo16</FONT> (ex
Ejemplo15) y <FONT FACE="Arial">miCanvas</FONT>:<BR>
<PRE>
<FONT SIZE=2>import java.awt.*;
<B>import java.util.*;
</B>import java.applet.Applet;

public class <B>Ejemplo16</B> extends Applet {
    public void init() {
<I>................ (esta parte no cambia)................
</I>    }
}

class miCanvas extends Canvas {
<B>    Vector v = new Vector();	// inicializamos con tama&ntilde;o indeterminado
				// Java se encarga de manejar la memoria necesaria!

</B>    public boolean mouseDown(Event e, int x, int y) {
<B>	v.addElement( new Rectangle(x, y, 0, 0) );	// nuevo elemento!
</B>	repaint();
	return false;
    }

    public boolean mouseDrag(Event e, int x, int y) {
<B>	Rectangle r = (Rectangle)v.lastElement();	// cast: <I>v</I> son rect&aacute;ngulos
	r.resize( x - r.x, y - r.y );			// (cre&eacute; <I>r</I> s&oacute;lo por claridad)
</B>	repaint();
	return false;
    }

    public boolean mouseUp(Event e, int x, int y) {
<B>	Rectangle r = (Rectangle)v.lastElement();	// cast: <I>v</I> son rect&aacute;ngulos
	r.resize( x - r.x, y - r.y );			// (cre&eacute; <I>r</I> s&oacute;lo por claridad)
</B>	repaint();
	return false;
    }

    public void paint(Graphics g) {
<B>	int i;					// contador de rect&aacute;ngulos
</B>	Dimension d = size();
	g.setColor(Color.red);
	g.drawRect(0, 0, d.width-1, d.height-1);
	g.setColor(Color.blue);
<B>	if (v.size() &gt; 0)
      for (i=0; i&lt;v.size(); i++) {
		Rectangle box = cortarRect( (Rectangle)v.elementAt( i ), d);
</B>		g.drawRect(box.x, box.y, box.width-1, box.height-1);
	      }
    }
<I>........................ (el resto no cambia) ........................
</I>}

Les sugiero utilizar un HTML que reserve espacio suficiente para ver todo el applet, como:
&lt;HTML&gt;
&lt;HEAD&gt;
&lt;TITLE&gt;Ejemplo 16 - Ejemplo con canvas&lt;/TITLE&gt;
&lt;/HEAD&gt;
&lt;BODY&gt;
&lt;applet code=&quot;Ejemplo16.class&quot; <B>width=300 height=250</B>&gt;
&lt;/applet&gt;
&lt;/BODY&gt;
&lt;/HTML&gt;<BR>
</FONT>
</PRE>
<P>
Veamos los pasos ahora. En primer lugar creamos una variable (global
a la clase) llamada <FONT FACE="Arial">v</FONT>, de clase <FONT FACE="Arial">Vector</FONT>,
y sin asignarle un tama&ntilde;o definido:
<PRE>
<FONT SIZE=2>Vector v = new Vector();<BR>
</FONT>
</PRE>
<P>
Al crear un nuevo rect&aacute;ngulo agregamos un elemento (objeto)
al vector mediante el m&eacute;todo <FONT FACE="Arial">add</FONT>:
<PRE>
<FONT SIZE=2>v.addElement( new Rectangle(x, y, 0, 0) );<BR>
</FONT>
</PRE>
<P>
Para acceder a un atributo de un objeto del vector no basta utilizar
directamente el vector, como:
<PRE>
<FONT SIZE=2>	v.lastElement().x<BR>
</FONT>
</PRE>
<P>
(<FONT FACE="Arial">lastElement()</FONT> nos permite acceder al
&uacute;ltimo elemento agregado al vector). Es necesario aclarar
expl&iacute;citamente que el elemento en cuesti&oacute;n es un
rect&aacute;ngulo, ya que el vector puede contener objetos de
cualquier tipo. Para eso usamos el <I>casting</I>:
<PRE>
<FONT SIZE=2>	<B>(Rectangle)</B>v.lastElement().x<BR>
</FONT>
</PRE>
<P>
En nuestro c&oacute;digo original reemplazar&iacute;amos por:
<PRE>
<FONT SIZE=2>(Rectangle)v.lastElement().resize( x - (Rectangle)v.lastElement().x, ......
<BR>
</FONT>
</PRE>
<P>
Pero es m&aacute;s claro si usamos una variable local de clase
Rectangle, le asignamos el mismo objeto que acabamos de agregar
al vector,  y lo usamos en su lugar:
<PRE>
<FONT SIZE=2>	Rectangle <B>r</B> = (Rectangle)v.lastElement();
	<B>r</B>.resize( x - <B>r</B>.x, y - <B>r</B>.y );<BR>
</FONT>
</PRE>
<P>
Finalmente, en el m&eacute;todo <FONT FACE="Arial">paint()</FONT>
no podemos asignar el elemento hasta no saber que existe (originalmente
el vector estaba vac&iacute;o!). As&iacute; que un <FONT FACE="Arial">if</FONT>
 nos permite verificar que el tama&ntilde;o del vector es mayor
que cero (tiene elementos), y un <FONT FACE="Arial">for</FONT>
nos permite dibujarlos uno por uno.
<P>
Se puede acceder a todos los elementos, uno por uno, mediante
el m&eacute;todo <FONT FACE="Arial">elementAt(x)</FONT>, que nos
da el x-&eacute;simo elemento del vector. El m&eacute;todo <FONT FACE="Arial">size()</FONT>
nos da la cantidad de elementos (el primero es el n&uacute;mero
0, y as&iacute;):
<PRE>
<FONT SIZE=2>	if (v.size() &gt; 0)
      for (i=0; i&lt;v.size(); i++) {
		Rectangle box = cortarRect( (Rectangle)v.elementAt( i ), d);
		g.drawRect(box.x, box.y, box.width-1, box.height-1);
	      }<BR>
</FONT>
</PRE>
<P>
Aqu&iacute; no hemos creado variables intermedias ya que igualmente
es claro (eso creo...).<BR>
<H2>Flicker molesto!</H2>
<P>
Bueno, el problema que nos queda es el molesto &quot;flicker&quot;,
o sea la manera en que titila el dibujo cuando movemos el mouse.
Esto es porque cada vez que se llama a <FONT FACE="Arial">paint()</FONT>,
el fondo se borra y se redibuja todo el canvas.
<P>
B&aacute;sicamente, la manera de evitarlo es reescribiendo el
m&eacute;todo <FONT FACE="Arial">update()</FONT>, que es el que
borra el fondo antes de llamar a <FONT FACE="Arial">paint()</FONT>
para que no lo borre; otro m&eacute;todo (que es el que vamos
a usar) es dibujar <I>no sobre la pantalla</I> sino sobre un &quot;buffer&quot;
gr&aacute;fico, y luego copiar ese buffer sobre la pantalla (lo
que es mucho m&aacute;s eficiente que dibujar sobre la misma).
<P>
Para eso vamos a crear un par de objetos:
<PRE>
<FONT SIZE=2>class miCanvas extends Canvas {
    Vector v = new Vector();
<B>    Image	imgBuff;
    Graphics	grafBuff;
</B>.............................<BR>
</FONT>
</PRE>
<P>
<FONT FACE="Arial">Image</FONT> es una clase abstracta, madre
de todas las clases que representan im&aacute;genes gr&aacute;ficas.
<FONT FACE="Arial">Graphics</FONT> es tambi&eacute;n abstracta
y nos permite obtener un contexto en el cual dibujar.
<P>
Lo que vamos a hacer es modificar nuestro m&eacute;todo <FONT FACE="Arial">paint()</FONT>
para que simplemente llame a <FONT FACE="Arial">update()</FONT>,
y redefinir el m&eacute;todo <FONT FACE="Arial">update()</FONT>:
<PRE>
<FONT SIZE=2>public void paint(Graphics g) {
<B>	update(g);
</B>}<BR>
</FONT>
</PRE>
<P>
El m&eacute;todo <FONT FACE="Arial">update()</FONT> es el que
har&aacute; todo el trabajo y b&aacute;sicamente es como nuestro
viejo <FONT FACE="Arial">paint()</FONT> con algunos agregados:
<PRE>
<FONT SIZE=2>public void update(Graphics g) {
	int i;
	Dimension d = size();

<B>if (grafBuff == null) {
		imgBuff = createImage(d.width, d.height);
		grafBuff = imgBuff.getGraphics();
}
grafBuff.setColor(getBackground());
grafBuff.fillRect(0, 0, d.width, d.height);
</B>	<I>grafBuff</I>.setColor(Color.red);
	<I>grafBuff</I>.drawRect(0, 0, d.width-1, d.height-1);
	<I>grafBuff</I>.setColor(Color.blue);
	if (v.size() &gt; 0) for (i=0; i&lt;v.size(); i++) {
		Rectangle box = cortarRect((Rectangle)v.elementAt(i), d);
		<I>grafBuff</I>.drawRect(box.x, box.y, box.width-1, box.height-1);
	}
<B>	g.drawImage(imgBuff, 0, 0, this);
</B>}<BR>
</FONT>
</PRE>
<P>
En <B>negrita</B> hemos indicado los agregados.
<P>
Si no est&aacute; creado todav&iacute;a (<FONT FACE="Arial">grafBuff==null</FONT>),
creamos nuestro buffer de dibujo. Para crear dicho buffer gr&aacute;fico
(de clase <FONT FACE="Arial">Graphics</FONT>), primero creamos
una imagen que en este caso tiene las mismas dimensiones que el
canvas (<FONT FACE="Arial">d.width</FONT> x <FONT FACE="Arial">d.height</FONT>),
y luego asignamos a <FONT FACE="Arial">grafBuff</FONT> el contexto
de dicha imagen mediante el m&eacute;todo <FONT FACE="Arial">getGraphics()</FONT>.
Imag&iacute;nense que con <FONT FACE="Arial">createImage(...)</FONT>
crean una &quot;pantalla virtual&quot;, y <FONT FACE="Arial">getGraphics()</FONT>
nos da una forma de acceder a esa pantalla como si fuera real.
<P>
Utilizando dicho contexto, elegimos como color el mismo color
de fondo del applet (<FONT FACE="Arial">getBackground()</FONT>)
y dibujamos un rect&aacute;ngulo lleno (<FONT FACE="Arial">fillRect(...)</FONT>),
borrando as&iacute; cualquier cosa que hubiera estado dibujada.
<P>
En <I>it&aacute;lica</I> hemos indicado las modificaciones a nuestro
m&eacute;todo anterior. Simplemente, en lugar de usar el contexto
de la pantalla (el par&aacute;metro <FONT FACE="Arial">g</FONT>
del m&eacute;todo), dibujamos sobre nuestro contexto-pantalla
virtual.
<P>
Finalmente, y para poder visualizar nuestro dibujo, usamos el
m&eacute;todo <FONT FACE="Arial">drawImage</FONT> sobre el contexto
de la pantalla real (<FONT FACE="Arial">g</FONT>), que copia nuestro
contexto <FONT FACE="Arial">imgBuff</FONT> en las coordenadas
(0,0) sobre la pantalla. Se hace tambi&eacute;n referencia al
canvas (...<FONT FACE="Arial">this</FONT>): el cuarto par&aacute;metro
de <FONT FACE="Arial">drawImage</FONT> es un objeto de clase <FONT FACE="Arial">ImageObserver</FONT>,
una interface que sirve para que el objeto dentro del cual se
dibuja reciba mensajes asincr&oacute;nicos que le indican c&oacute;mo
est&aacute; siendo construida la imagen, y cu&aacute;ndo est&aacute;
lista.<BR>
<H2>Animate!</H2>
<P>
Si bien puede ser un poco m&aacute;s complejo de entender que
un dibujo directo sobre la pantalla, notar&aacute;n que la implementaci&oacute;n
es directa y no trae ning&uacute;n problema. Esta misma aproximaci&oacute;n
puede utilizarse para crear animaciones.
<P>
En este ejemplo, para manejar la ejecuci&oacute;n cuadro a cuadro
de la animaci&oacute;n, usamos <I>Threads</I>. No se preocupen
por eso, lo veremos pronto. &Uacute;nicamente tengan en cuenta
que nuestro applet debe implementar la clase <I>runnable</I>,
y el thread se encarga de ejecutar el m&eacute;todo <FONT FACE="Arial">run()</FONT>
que simplemente llama a <FONT FACE="Arial">repaint()</FONT> y
espera 100 milisegundos entre cuadro y cuadro.
<P>
El trabajo de c&aacute;lculo y dibujo lo hace <FONT FACE="Arial">update()</FONT>.
Se los dejo para que lo estudien; no es nada complicado y tambi&eacute;n
usa doble buffering (como el ejemplo anterior).<BR>
<PRE>
<FONT SIZE=2>import java.awt.*;
import java.util.*;
import java.applet.Applet;

public class Ejemplo18 extends Applet implements Runnable {

    Thread	animador;
    Image	imgBuff;
    Graphics	grafBuff;
    double ang = 0.0;

    public void init() {
	resize(new Dimension (200,200));
    }

    public void start() {
	if (animador == null) animador = new Thread(this);
	animador.start();
    }

    public void run() {
	while (Thread.currentThread() == animador) {
		repaint();
		try {
			Thread.sleep(100);
		}
		catch (InterruptedException e) {
			break;
		}
	}
    }

    public void update(Graphics g) {
	int i;
	int dx, dy;

	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);
	dx = (int)(50 * Math.abs(Math.cos(ang)));
	dy = (int)(50 * Math.abs(Math.sin(ang)));
	ang = ang + 0.1;
	if (ang&gt;2*Math.PI) ang = 0.0;
	grafBuff.drawRect(100-dx, 100-dy, 2*dx, 2*dy);

	g.drawImage(imgBuff, 0, 0, this);
    }
}<BR>
<BR>
</FONT>
</PRE>
<P>
Como siempre, me despido hasta la clase que viene...<BR>
<BR>
<P>
Jorge Bourdette
<P>
<A HREF="jpb@amarillas.com" >jpb@amarillas.com</A><BR>
</BODY>
</HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -