Buscar
Social
Ofertas laborales ES
« Uso de las interfaces de Java | Main | Mapeo de XML a Java (Parte 1) »
martes
may152001

Gráficos en Java (Parte 1)

Introducción al tratamiento gráfico: La clase Graphics.





En este artículo nos centraremos en conocer qué es y cómo trabaja la clase Graphics. Dicha clase, que pertenece al paquete java.awt es el sistema básico para todas las operaciones relacionadas con el uso de gráficos en Java y soporta un gran surtido de métodos posibilitándole al programador dibujar o colocar imágenes dentro de un componente. Veremos también las técnicas y métodos que se emplean para "pintar" y en el ejemplo mostraré algunas de las formas básicas que esta clase nos proporciona.



La clase Graphics.




La clase Graphics es el sistema básico de todas las operaciones gráficas por lo que parece fundamental que se entienda bien su concepto antes de ponernos a tratar gráficos o imágenes. Esta clase abstracta tiene la misión de conformar el contexto gráfico y la de proporcionar los métodos necesarios para poder dibujar en la pantalla.



El contexto gráfico.




Consiste en encapsular la información necesaria para las operaciones de renderizado básicas, es decir, toda la información que afecte a las operaciones de dibujado conforma el contexto gráfico y la salida a la ventana en la que se va a dibujar tiene que pasar por este contexto. Incluye las siguientes propiedades más importantes:





  • El objeto Component sobre el que se va a dibujar. Puede ser la ventana principal de un applet, de un frame o de una ventana hija.
  • Un origen de coordenadas. Se especifican en pixels y comienzan en la esquina superior izquierda (0,0). No obstante, recordar que las coordenadas son relativas a la ventana en la que estemos trabajando ya que la posición real que ocupa una ventana madre en la pantalla no tiene porqué ser la misma que la de una ventana hija que despleguemos en algún momento.
  • El "clipping". Esto no es más que una ventana (un rectángulo invisible) sobre el que vamos a poder pintar o renderizar nuestras imágenes. Todo lo que quede fuera será cortado (clipped).
  • Los colores del fondo y el primer plano (backgroun y foreground). Por defecto son negro y blanco respectivamente.
  • La fuente de texto. Por defecto es la fuente Dialog, estilo plano y 12 pulgadas.




Pero para dibujar, nuestro programa necesita un contexto gráfico válido que vendrá dado a través de una instancia o ejemplar de la clase Graphics. El problema es que al ser una clase abstracta, ésta no se puede instanciar directamente por lo que lo que habrá que hacer es pasarle el contexto al programa a través de los métodos paint() o update() o bien, que el programa obtenga el contexto mediante el método getGraphics() de la clase Component().




En este artículo nosotros obtendremos una instancia de la clase Graphics a través de los métodos paint() o update().



Los métodos




Graphics nos debe proporcionar todos los métodos necesarios para poder dibujar formas básicas, texto con todas las fuentes que tiene el sistema así como permitirnos cargar imágenes. Todo lo que portemos a la ventana de renderizado se hará a través de estas funciones.



paint(), repaint() y update().




Estos 3 métodos son los encargados de mostrar los gráficos. Java nos proporciona una versión por defecto en la clase Component por lo que tendremos que sobrecargar update() y paint() para que nuestro programa pinte lo que deseemos y como queramos.




Cuando el usuario llama al método repaint() de un componente, el AWT (recondando que Swing es "algo asi" como una extensión de AWT) llama al método update() de ese componente, que por defecto llama al método paint().



paint().




Su sintáxis es:




public void paint(Graphics g)



Es el responsable de dibujar las imágenes. Normalmente es el sistema operativo el que lo llama al dibujar la ventana por primera vez, volviéndolo a llamar cada vez que entiende que la ventana o una parte de ella debe ser redibujada (por ejemplo, por haber estado tapada por una ventana y quedar de nuevo a la vista). Esta llamada la hace a través del método update().



update().




Su sintáxis es:




public void update(Graphics g)




Este método se llama en respuesta a una solicitud por parte del método repaint(), por el AWT o por el programador cuando ha realizado un cambio en la ventana de renderización y necesita que se dibuje de nuevo.




La implementación por defecto trabaja "borrando" la escena actual mediante un repintado del mismo color que el de background y luego llama al método paint() para pintar la nueva escena. Esta técnica provoca el molesto efecto llamado parpadeo (flickering) el cual se puede solucionar redefiniendo el método update() de manera que solo actualice la zona de pintado donde se han hecho modificaciones, o bien, como veremos en un artículo posterior, empleando la técnica del doble buffer.



repaint().




Su sintáxis es:




public void repaint()
public void repaint(long tm)
public void repaint(int x, int y, int w, int h)
public void repaint(long tm, int x, int y, int w, int h)



Este método solicita que un componente sea repintado llamando lo más pronto posible al método update() del componente. De las posibles sintáxis que disponemos se extrae que el repintado puede ser inmediato, transcurrido un tiempo (mseg) o repintar solo la zona rectangular especificada en los parámetros. Esta última técnica es de gran utilidad cuando el repintado de la escena consume mucho tiempo, así solo repintamos la franja que se haya modificado.




Para reducir el tiempo que se tarda en repintar, el AWT toma dos técnicas:





  • Repintar solo aquellos componentes que necesitan repintarse, bien porque se han cubierto por otro componente o bien porque el programador así lo solicitó.
  • Si un componente se tapa parcialmente por otro, cuando se le devuelve a primer plano, solo se repinta la zona cubierta.



Redibujar en Swing.




Todo lo dicho anteriormente necesita ser ligeramente corregido en caso de trabajar con componentes Swing, es decir, si vamos a pintar sobre un JFrame o un JApplet. Esto se debe a que estas dos clases definen su propio método update(Graphics g) pero éste lo que hace es tan solo llamar al método paint(), es decir, no limpia la pantalla cada vez que se necesita repintar la escena como ocurría con AWT. Se hace por tanto necesario sobrecargar este método como se puede ver en el ejemplo.



Poniéndolo todo junto.




En el siguiente ejemplo se muestran algunas de las primitivas gráficas que la clase Graphics incorpora. No las comento en el artículo porque su sintáxis es sencilla. La explicación de todas y cada una de ellas lo puedes encontrar en las especificaciones HTML del API de Java.




Así mismo, seguiremos el movimiento del ratón por la ventana de pintado para ver cómo actua el método repaint() y cómo implementar un método update() que reduzca lo más posible el parpadeo (flickering) (aunque cada problema requerirá su solución particular).




//Fichero FormasBasicas.java

/*
<applet code = "FormasBasicas" width = 600 height = 300>
</applet>
*/

import java.awt.Graphics;
import java.awt.Color;
import java.awt.Dimension;

import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;

import javax.swing.JApplet;

public class FormasBasicas extends JApplet implements MouseMotionListener {

Dimension d;
int coordX[] = {250,350,330,350,250,270,250};
int coordY[] = {100,100,125,150,150,125,100};
int puntos = 7;
//variables para almacenar la posición actual del mouse
int posX = 0, posY=0;
//variables para recordar la posición anterior del mouse
int memX = 0, memY=0;

public void init() {
d = this.getSize();
addMouseMotionListener(this);
}

public void mouseDragged(MouseEvent me) {}

public void mouseMoved(MouseEvent me) {
this.showStatus("Coordenadas en : " +me.getX() + ", " + me.getY());
posX = me.getX();
posY = me.getY();
this.repaint();
}

/*
En esta implementación de update() trato de "disimular" el flickering, para
ello voy borrando el rastro que va dejando el mouse repintándolo de blanco.
*/

public void update(Graphics g) {
g.setColor(Color.black);
g.drawLine(0,posY,d.width-1,posY);
g.drawLine(posX,0,posX,d.height-1);
g.setColor(Color.white);
if (memY != posY) {
g.drawLine(0,memY,d.width-1,memY);
memY = posY;
}
if (memX != posX) {
g.drawLine(memX,0,memX,d.height-1);
memX = posX;
}
g.setColor(Color.black);
this.paint(g);
}

/*
Este es el update() básico, como trabaja en el AWT, solo que lo he
implementado porque estoy trabajando con Swing. Juega con ambos para
que observes la diferencia y lo molesto que puede llegar a ser el parpadeo.
*/

/*public void update(Graphics g) {
g.setColor(Color.white);
g.fillRect(0,0,d.width-1,d.height-1);
g.setColor(Color.black);
g.drawLine(0,posY,d.width-1,posY);
g.drawLine(posX,0,posX,d.height-1);
this.paint(g);
}*/

/*
Aquí pintamos todas las figuras. Observa que al pasar por las figuras
sólidas las líneas que nos señalan la posición del ratón parpadean y/o
desaparecen. Podríamos haber puesto todo este código dentro del método
update() y haber reducido aun más el efecto del parpadeo.
*/
public void paint(Graphics g) {
g.drawRect(0,0,d.width-1,d.height-1);
g.drawLine(10,10,110,60);
g.setColor(Color.green);
g.fillRect(130,10,100,50);
g.setColor(Color.orange);
g.drawRoundRect(250,10,150,50,20,20);
g.setColor(Color.blue);
g.fillArc(10,100,100,50,90,270);
g.setColor(Color.magenta);
g.drawOval(130,100,100,50);
g.setColor(Color.red);
g.fillPolygon(coordX,coordY,puntos);
g.setColor(Color.gray);
g.drawString("Linea",10,80);
g.drawString("Rectangulo sólido",130,80);
g.drawString("Rectángulo redondeado",250,80);
g.drawString("Arco sólido",10,170);
g.drawString("Elipse",130,170);
g.drawString("Un poligono propio",250,170);
g.drawString("Este texto queda cortado", d.width-60,170);
}
}




  • Puedes conseguir el código fuente de este artículo aquí: código
  • Si tienes instalado el plug-in de Java2 en tu ordenador puedes comprobar el applet aqui: applet



Próximo artículo




A partir del próximo artículo nos meteremos a estudiar el API Java 2D empezando por la clase Graphics2D. Si bien este artículo es introductorio al tratamiento de gráficos, la clase Graphics2D extiende de la clase Graphics por lo que rápidamente se deduce que es más potente. Es por ello que a partir de ahora trabajaremos con esta última.
















Leo Suarez es un Ingeniero Superior de Telecomunicaciones por la
Universidad de Las Palmas de Gran Canaria con todas sus letras, que no
son pocas, y trabaja como tal en Santa Cruz de Tenerife.
Cuando no
está saltando de isla en isla o escribiendo para javaHispano aprovecha
para disfrutar con la novia y los amigos del estupendo clima de las islas afortunadas.

Para cualquier duda o tirón de orejas, e-mail a:
leo_ARROBA_javahispano.com




Reader Comments

There are no comments for this journal entry. To create a new comment, use the form below.
Comentarios deshabilitados
Comentarios deshabilitados en esta noticia.