Graficos

download Graficos

If you can't read please download the document

Transcript of Graficos

Grficos

Anterior | SiguienteCap.Anterior | Cap.Siguiente

El Sistema de Coordenadas

Pintando con AWT El mtodo paint()

Componentes Lightweight

Normas para pintar con AWT

Pintando con Swing Soporte de Doble Buffer

Propiedades Adicionales de Pintado

Opacidad

Redibujo Optimizado

Los mtodos paint()

Repintado e Interfaz de Usuario

Proceso de Repintado

Repintado Sncrono

La clase RepaintManager El objeto RepaintManager Actual

Control del objeto RepaintManager Actual

Control global sobre el Doble Buffer

Normas para Pintar con Swing

La clase Graphics Mtodos Generales Obtener un Contexto Grfico

Crear un Objeto Graphics

Copiar y Borrar

Traslacin del Origen

Pintar Normal y Xor

Mtodos para Pintar Figuras

Mtodos para Pintar Texto La clase Font

La clase FontMetrics

Mtodos de Clipping

Mtodos para Manejo de Imgenes La clase Color

El mtodo drawImage()

La clase Image

El interfaz ImageProducer

La clase MediaTracker

Animacin

Uso Avanzado de Imgenes Interfaces

La clase ColorModel La clase IndexColorModel

La clase DirectColorModel

La clase FilteredImageSource

La clase ImageFilter

La clase MemoryImageSource

La clase PixelGrabber

Ejemplo

Toda la parte grfica de Java se base en la clase Graphics, por lo que esta seccin de Tutorial se dedicar casi exclusivamente al uso de esta clase para manejar formas, fuentes de caracteres e imgenes sobre la pantalla. Y, aunque para el uso normal de grficos no sea necesario, por lo que el lector puede obviar esa parte, se ha incluido un amplio repaso al sistema de repintado de Java, de forma que si el lector tiene curiosidad por saber exactamente como funciona el sistema de repintado y poder crear sus propios mecanismos, tenga suficiente informacin como para acometer esa tarea, no sin esfuerzo, pero al menos, s con los conocimientos suficientes.El Sistema de CoordenadasCada uno de los Componentes de Java tiene su propio sistema de coordenadas, que va desde la posicin (0,0) hasta la posicin determinada por su anchura total y altura total, menos una unidad; la unidad de medida son pixels de pantalla. Como se puede apreciar en la figura siguiente, la esquina superior izquierda del Componente es la posicin que coincide con las coordenadas (0,0). La coordenada en el eje de abscisas se incrementa hacia la derecha y en las ordenadas hacia abajo.

A la hora de pintar un Componente, se debe tener en cuenta adems del tamao de ese Componente, el tamao del borde del Componente, si lo tuviera. Por ejemplo, un borde que ocupa un pixel alrededor de un Componente, hara que la coordenada de la esquina superior izquierda pasase de ser (0,0) a ser ahora (1,1), y reduciendo adems la anchura y altura totales del Componente en dos pixeles, uno por cada lado.Las dimensiones de un Componente se pueden conocer a travs de sus mtodos getWidth() y getHeight(). El mtodo getInsets(), permite conocer el tamao del borde. El siguiente trozo de cdigo muestra la forma de conocer exactamente la anchura y altura de la zona disponible, en un Componente, para poder pintar en su interior.public void paintComponent( Graphics g ) {...Insets borde = getInsets();int anchura = getWidth() - borde.left - borde.right;int altura = getHeight() - borde.top - borde.bottom;.../* La primera posicin disponible para pintar sera (x,y), donde x es al menos borde.left, e y es al menos borde.height*/}El ejemplo siguiente, java1501.java, permitir al lector familiarizarse con el sistema de coordenadas. La figura representa la ventana que aparece en pantalla cuando se ejecuta el ejemplo como aplicacin independiente, ya que tambin se puede ver en un navegador. Cuando se pulsa el botn del ratn con el cursor dentro de la zona enmarcada, aparecer un punto en esa posicin y en la parte inferior de la ventana, se indicarn las coordenadas correspondientes a la posicin en que apareci el punto. Si se pulsa exactamente sobre el marco de la zona, las coordenadas s aparecen, pero el punto no se visualizar debido a que el borde del componente se redibuja posteriormente a las acciones de repintado generadas por el usuario. Si se quiere eliminar este efecto, es suficiente con colocar el Componente en otro JPanel que lo contenga.

El programa es muy sencillo, y semejante al ejemplo java1102.java presentado al hablar del AWT. Se implementan dos Componentes, el mayor es la zona rectangular con borde que es el origen de los eventos de ratn que se van a recoger y donde se muestra grficamente a travs de un punto y sus coordenadas, el sitio exacto en que se encontraba el cursor del ratn en el momento de pulsar el botn, y el otro Componente es la etiqueta que se presenta en la parte inferior sonde se vuelve a mostrar la coordenada en que se ha pulsado el ratn.

Pintando en AWT

Anterior | Siguiente

Antes de entrar en ms profundidades, tanto en la revisin de grficos en AWT, en Swing o en el API 2D, es necesario entender exactamente cmo funciona el mecanismo de repintado que utiliza Java, para poder comprender como se producen y recogen los eventos que redibujan el contenido de los Componentes. En AWT hay dos mecanismos por los que se producen las operaciones de repintado, dependiendo de quin sea el que ordena ese repintado, el sistema o la aplicacin.En el caso de que sea el sistema el que ordena el repintado, l es quien indica a un Componente que debe regenerar su contenido, y las razones ms normales por las que hace esto son:El Componente se hace visible por primera vez en la pantalla

El Componente ha cambiado de tamao

El Componente se ha deteriorado y necesita ser regenerado; por ejemplo, estaba medio tapado por otro Componente que ahora se ha movido, con lo cual hay una zona del Componente que estaba oculta y ahora debe mostrarse

En el caso de que el repintado sea ordenado por la aplicacin, es el propio Componente el que decide la necesidad de la actualizacin; normalmente, debido a algn cambio en su estado interno, por ejemplo, un botn detecta que el ratn ha sido pulsado sobre l y determina que tiene que cambiar su imagen de botn normal a botn pulsado.El Mtodo paint()callback para ese repintado, que es igual tanto para los Componentes normales como para los Componentes lightweight. Esto significa que un programa debe colocar su cdigo de repintado dentro de un mtodo sobrecargado, y ser Java quin se encargar de invocarlo en el momento del repintado. Este mtodo se encuentra en java.awt.Component.Independientemente de quin sea el originador de la peticin de repintado, el AWT utiliza un mecanismo de callback para ese repintado, que es igual tanto para los Componentes normales como para los Componentes lightweight. Esto significa que un programa debe colocar su cdigo de repintado dentro de un mtodo sobrecargado, y ser Java quin se encargar de invocarlo en el momento del repintado. Este mtodo se encuentra en java.awt.Component.public void paint( Graphics g )Cuando el AWT llama a este mtodo, el objeto Graphics que se pasa como parmetro est preconfigurado con el estado adecuado al pintado en ese Componente determinado:El color del objeto Graphics se fija a la propiedad foreground del Componente

La fuente de caracteres se fija a la propiedad font del Componente

La traslacin tambin se determina, teniendo en cuenta que la coordenada (0,0) representa la esquina superior-izquierda del Componente

El rectngulo de recorte, o clipping, se fija al rea del Componente que es necesario repintar

El programa debe utilizar este objeto Graphics, o uno derivado de l, para redibujar la salida. Es el encargado de cambiar el estado del objeto Graphics como sea necesario. Por ejemplo, el cdigo siguiente muestra la forma de crear un crculo relleno dentro de los lmites del Componente.public void paint( Graphics g ) {// Se calcula el tamao de la zonaDimension tam = getSize();// Ahora el dimetroint d = Math.min( tam.width,tam.height ); int x = (tam.width - d) / 2;int y = (tam.height - d) / 2;

// Se pinta el crculo, fijando el color al de frenteg.fillOval( x,y,d,d );// Se pinta la circunferencia de borde, en color negrog.setColor( Color.black );g.drawOval( x,y,d,d );}El ejemplo java1502.java, es un poco ms entretenido que el cdigo anterior, pero en esencia es igual, y proporciona al lector un buen ejemplo de cmo se utiliza el mtodo paint() en un programa AWT. La imagen que genera el ejemplo es la que reproduce la figura.

En general, se debe evitar en todos los programas, escribir cdigo que dibuje algo, fuera del mbito del mtodo paint(). El porqu, se debe a que ese cdigo puede ser invocado a veces cuando no es adecuado que se haga; por ejemplo, antes de hacer visible al Componente o tener acceso a un objeto Graphics vlido. No es nada recomendable que los programas invoquen directamente al mtodo paint().Para habilitar el pintado desde las aplicaciones, AWT proporciona los siguientes mtodos, que pueden ser llamados en cualquier momento para solicitar un repintado del Componente afectado, son mtodos de java.awt.Component, por supuesto.public void repaint()public void repaint( int x,int y,int width,int height )public void repaint( long tm )public void repaint( long tm,int x,int y,int width,int height )En las lneas de cdigo siguientes se muestra un ejemplo muy simple de un receptor de eventos de ratn que utiliza el mtodo repaint() para actualizar un componente terico de tipo botn en el momento en que el ratn sea pulsado y soltado.MouseListener procesoRaton = new MouseAdapter() {public void mousePressed( MouseEvent evt ) {MiButon b = (MiBoton)evt.getSource();b.setSelected( true );b.repaint();}

public void mouseReleased( MouseEvent evt ) {MiButon b = (MiButon)evt.getSource();b.setSelected( false );b.repaint(); }};Los componentes que realicen operaciones complejas, deberan invocar al mtodo repaint() con argumentos definiendo solamente la regin que necesita actualizacin. Un error muy comn es llamar a repaint() sin ningn parmetro, lo que hace que se repinte el componente completo, lo que har, sin lugar a dudas, que se realicen repintados que no son necesarios.El lector se estar preguntando el porqu de la distincin entre el pintado desde el sistema y el pintado desde la aplicacin. La respuesta a esa pregunta se basa en la forma en que trata estos casos el AWT en el caso de los componentes normales, los componentes lightweight se discutirn posteriormente, lo que puede generar un poco de confusin.En los componentes normales, o heavyweight, los dos tipos de origen del repintado se producen de dos formas distintas, dependiendo de que la operacin sea ordenada por el sistema o por la aplicacin.En el caso de que sea el sistema el que ordena el repintado:El AWT determina si el componente necesita ser repintado completamente o solamente parte de l

El AWT lanza el evento para invocar al mtodo paint() sobre el componente

Si quin ordena el repintado es la aplicacin, lo que sucede es lo siguiente:El programa determina si parte o todo el componente debe ser repintado, en respuesta a cambios en algn estado interno

El programa invoca al mtodo repaint() sobre el componente, el cual lanza una peticin al AWT indicndole que ese componente necesita ser repintado

El AWT lanza el evento para invocar al mtodo update() sobre el componente. En el caso se que se produzcan mltiples llamadas al mtodo repaint() antes de que se inicie el repintado, todas estas llamadas se remiten a una; el algoritmo que determina cuando hay mltiples llamadas que pueden ser comprimidas en una sola es dependiente de la implementacin. En el caso de que el colapso de todas estas llamadas se produzcan, el rectngulo resultante que se actualizar ser la unin de los rectngulos indicados en cada una de las peticiones de repintado

Si el componente no sobrecarga el mtodo update(), la implementacin por defecto de update() limpia el fondo del componente (si no se trata de un componente lightweight) y luego hace una llamada a paint()

El problema est en que al ser el resultado final el mismo, una llamada al mtodo paint(), mucha gente no entiende el propsito de tener un mtodo update() separado. Aunque esto es verdad en la implementacin por defecto de update(), porque se limita a dar un rodeo para llamar a paint(); aqu hay una forma de que un programa pueda controlar los repintados provocados por la aplicacin de forma distinta, si se quiere. Un programa debe asumir que una llamada a paint() implica que el rea definida por el rectngulo que se va a repintar est daada y debe ser repintada completamente; sin embargo, una llamada a update() no implica esto, sino que posibilita al programa a realizar un repintado incremental.Este repintado incremental es til, por ejemplo, si un programa desea actualizar una capa por encima de las ya existentes en el componente. El ejemplo java1503.java, es un programa que se beneficia del uso de update() para realizar este repintado incremental. Al ejecutarlo, aparecern dos ventanas en las cuales se van a ir pintado lneas que unirn cada uno de los puntos en que se pulse el ratn. El lector podr comprobar la diferencia de realizar acciones en una y en otra. El cdigo del ejemplo es el que se reproduce.import java.awt.*;import java.awt.event.*;import java.util.Vector;

public class java1503 {public static void main(String[] args) {WindowListener conclusion = new WindowAdapter() {public void windowClosing( WindowEvent evt ) {System.exit( 0 );}};

// Se crea el Frame en el que se utiliza paint() directamenteFrame f1 = new Frame( "Parpadeo - Pulsa el ratn para pintar lneas" );f1.addWindowListener( conclusion );f1.add( new MiCanvas( new Vector()),BorderLayout.CENTER );f1.pack();f1.show();

// Se crea el Frame en el que se realiza el repintado incremental a// travs de update()Frame f2 = new Frame( "Suavidad - Pulsa el ratn para pintar lneas" );f2.addWindowListener( conclusion );f2.add(new MiCanvasSuave( new Vector()),BorderLayout.CENTER );f2.pack();// Recogemos los lmites del Frame anterior, para colocar el nuevo// a continuacinRectangle limF1 = f1.getBounds();f2.setLocation( limF1.x+limF1.width,limF1.y );f2.show(); }}

// Esta clase es un Canvas que grnera un fondo semicomplejo con vectores// que se van creando segn se va haciendo click en diferentes posiciones// de ese canvas.// Pinta el rea completa dentro de paint()class MiCanvas extends Canvas {// Fijamos el array de colores que se va a utilizar para pintar los// vectores y que el fondo sea cada vez ms multicolorprotected Color colores[] = {Color.red, Color.yellow, Color.blue,Color.green, Color.pink, Color.orange,Color.white, Color.magenta, Color.cyan};protected Vector puntos;protected int vectoresPintados;

public MiCanvas( Vector puntos ) {this.puntos = puntos;

// Clase anidada para recoger los eventos de pulsacin del botn// delr atnaddMouseListener( new MouseAdapter() {public void mousePressed( MouseEvent evt ) {MiCanvas c = (MiCanvas)evt.getSource();// Se incorpora un nuevo vectorc.puntos.addElement( evt.getPoint() );c.repaint(); }});}

public Dimension getPreferredSize() {// Tamao del Canvasreturn new Dimension( 400,400 );}

/*El lector puede descomentar este mtodo para comprobar que sise sobreescribe el mtodo update() sin BORRAR el fondo, se veafectado el parpadeo. No obstante, aunque ese parpadeo es menosdramtico, todava se nota que se produce

public void update( Graphics g ) {paint( g );}*/

public void paint( Graphics g ) {// Se repinta todo, primero el fondo...pintaFondo(g);// ...y a continuacin, todos los vectoresvectoresPintados = 0;for( int i=0 ; i < puntos.size()-1; i++ ) {pintaVector( g,i );}}

// Mtodo empleado para pintar el fondoprotected void pintaFondo( Graphics g ) {Dimension dim = getSize();int grosor = 5;int x = 0;

// Se pintan rectngulos que van ocupando toda la ventana// del tamao que se indica en el parmetro grosorfor( int y=0; y+grosor

Antes de presentar la clase Graphics, quiz resulte ms interesante para el lector la entrada a saco con una pequea aplicacin. El ejemplo java1507.java, muestra al lector el uso de la clase Canvas y varios de los mtodos de la clase Graphics. El programa utiliza una tcnica muy simple para crear dos botones, con apariencia de objetos 3D. Observe el lector que estos botones 3D no estn construidos en base a la clase Button, o usando el mtodo draw3Drect() de la clase Graphics; en vez de ello, se ha utilizado la llamada al mtodo drawRect() de la clase Graphics, que pinta un rectngulo 2D, proporcionando el efecto 3D como resultado artificial creado durante el proceso de dibujo.Cuando el programa arranca, aparecen dos botones en la pantalla sobre un objeto Frame, que llevan por rtulo Corto y Largo, y un tercer botn, rotulado como Boton, que s es una instancia de clase Button. La imagen siguiente reproduce esta situacin inicial.

Los botones verdes aparecen de forma que sobresalen de la superficie del Frame, de forma similar a como lo hace el objeto Button autntico. Cuando se coloca el cursor sobre uno de los botones verdes y se pulsa el ratn, ese botn tambin se hundir de forma semejante a cmo lo hace el botn real, volviendo a su posicin anterior en el momento en que se suelte el botn del ratn.Como lo cierto es que esto es una ilusin ptica, puede que algunos de los lectores no sean capaces de ver el efecto, en el caso de que solamente vean rectngulos verdes con un texto en su interior. El efecto 3D es una forma artificial creada al pintar un rectngulo sobre un objeto Canvas. Los falsos botones son instancias de una clase que es subclase de la clase Canvas; el ejemplo se aprovecha de esto para poder sobrescribir el mtodo paint() y fijar el tamao y color del objeto Canvas, pintar un rectngulo que est parcialmente visible y parcialmente invisible, y dibujar un texto sobre ese objeto Canvas. El hecho de que el rectngulo est parcialmente visible, es el que creer al ojo del lector que el objeto Canvas sobresale de la pantalla, o se hunde, aparentando as tener tres dimensiones.El rectngulo se pinta con un pequeo desplazamiento hacia derecha y abajo, en relacin con el objeto Canvas, o al revs. En ambos casos, hay dos lneas del rectngulo que se pierden, porque se salen de los lmites del objeto Canvas; las dos lneas que quedan visibles son las que simulan las sombras que produce el efecto 3D. En el momento de pulsar el botn del ratn sobre el falso botn de la pantalla, en la consola se muestra el mensaje de que efectivamente eso se ha producido, al igual que se hace cuando se pulsa el botn creado instanciando la clase Button.Hay una circunstancia curiosa que el lector puede comprobar, y es que el falso botn responde mucho ms rpidamente que el botn real, al menos en la mquina del autor, Pentium II a 350 MHz con Windows NT. Se puede demostrar pulsando rpida y repetidamente sombre uno y otro. El botn real parece que pierde algunos de los clicks mientras que el botn falso responde a todos ellos, o por lo menos, a un porcentaje mucho mayor de lo que lo hace el botn real. A continuacin se reproduce el cdigo completo del ejemplo.import java.awt.*;import java.awt.event.*;

// Esta es la clase que crea el falso botn. Se sobreescribe el mtodo// paint() para fijar el tamao y color del objeto Canvas, para pintar// un rectngulo parcialmente oculto sobre ese objeto Canvas, y para // escribir un texto sobre el objeto Canvas.// El hecho de que el rectngulo que se pinta est parcialmente oculto// es lo que hace que parezca que el botn sobresale del Canvas, o que// d la impresin de que se hunde al pulsar sobre l.// El offset con que se pinta el rectngulo es el que hace que haya dos// lneas que se pierdan, semejando a las sombras que provocan la// ilusin del efecto 3Dclass BotonFalso extends Canvas {boolean pulsado = false; // Indica si el botn est pulsado o noint ancho; // Anchura deo botn en pixelsint alto; // Altura del botn en pixelsString rotulo; // Texto del botn

// Constructor del Falso Botnpublic BotonFalso( int _ancho,int _alto,String _rotulo ) {this.width = _ancho;this.height = _alto;this.caption = _rotulo;this.setBackground( Color.green );this.setSize( this.width,this.height );}

public void paint( Graphics g ) {// Determinamos el desplazamiento segn la situacin en que se// encuentre el botn y se pinta el rectngulo sobre el objeto Canvasif( pulsado ) g.drawRect( 1,1,ancho,alto );else g.drawRect( -1,-1,ancho,alto );

// Se escribe el texto del rtulo del botn centrado horizontalmente// y ligeramente desplazado verticalmente. Para este desplazamiento// vertical, se utiliza 1/4 de la altura de la fuente de caracteres// que se est utilizando, para calcular la lnea base sobre la que// se van a colocar los caracteres del textoint altoFuente = g.getFontMetrics().getHeight();int anchoCadena = g.getFontMetrics().stringWidth( rotulo );g.drawString( rotulo,(ancho-anchoCadena)/2,(height/2)+(altoFuente/4) );}}

// Clase de control del ejemplo, con el mtodo main() para poder lanzarla // como aplicacin individualclass java1507 extends Frame {public static void main( String[] args ) {// Se instancia un objeto de la clasenew java1507();}

// Constructorpublic java1507() {this.setLayout( new FlowLayout() );this.setTitle( "Tutorial de Java, Grficos" );this.setSize( 300,80 );

// Se instancian dos botones falsos de tamaos diferentes y un botn// real instanciando un objeto de la clase ButtonBotonFalso botFalsoCorto = new BotonFalso( 40,20,"Corto" );BotonFalso botFalsoLargo = new BotonFalso( 80,20,"Largo" );Button botAutentico = new Button( "Boton" );

// Se aaden todos los botones al objeto Framethis.add( botFalsoCorto );this.add( botAutentico );this.add( botFalsoLargo );// Se hacen visibles this.setVisible( true );

// Receptor de eventos del ratn, que se registra para que reciba los// eventos de ratn que se generen sobre los dos botones falsosProcesoRaton procesoRaton = new ProcesoRaton();botFalsoCorto.addMouseListener( procesoRaton );botFalsoLargo.addMouseListener( procesoRaton );

// Se instancia y registra un objeto receptor de los eventos de tipo// Action que se generen sobre el botn real de tipo ButtonbotAutentico.addActionListener( new ProcesoBoton() );

// Se instancia y registra un objeto recetor de los eventos sobre la// ventana para que termine decentemente la ejecucin cuando se cierre// esa ventanaProcesoVentana procesoVentana = new ProcesoVentana();this.addWindowListener( procesoVentana ); }}

// Esta clase es la que se utiliza para instanciar un objeto que reciba// los eventos del ratn que se produzcan sobre los botones falsos y hace// que las imagen visual del botn falso cambie entre "pulsado" y normal// para simular el efecto que se produce en los botones normales de// que se hunden cuando se pulsa sobre ellosclass ProcesoRaton extends MouseAdapter {// Se sobreescribe el mtodo que recibe los eventos de pulsacin del// ratnpublic void mousePressed( MouseEvent evt ) {// Se fija la variable de que est el botn pulsado y se repinta((BotonFalso)evt.getComponent()).pulsado = true;evt.getComponent().repaint();}

// Se sobreescribe el mtodo que recibe los eventos de que el ratn// se ha soltadpopublic void mouseReleased( MouseEvent evt ) {// Se presenta un mensaje en consola para indicar que el botn se// ha soltadoSystem.out.println( "mouseReleased" );// Se fija la variable de que el botn del ratn se ha liberado y// se repinta el botn sobre el Canvas((BotonFalso)evt.getComponent()).pulsado = false;evt.getComponent().repaint();}}

// Esta clase es la que se utiliza para instanciar un objeto que reciba// los eventos de tipo Action que se producen cuando se pulsa sobre un// botn normal instanciado de la clase Button.class ProcesoBoton implements ActionListener {public void actionPerformed( ActionEvent evt ) {// Se presenta un mensaje en consola indicando el tipo de evento para// que se sepa que se ha pulsado el botn normalSystem.out.println( "actionPerformed" );}}

// Este es el receptor utilizado para concluir el programa cuando el// usuario pulsa sobre el botn de cerrar la ventana situado en el// marco de esa ventanaclass ProcesoVentana extends WindowAdapter {public void windowClosing( WindowEvent evt ) {System.exit( 0 );}}Los ejemplos java1508.java y java1509.java, son versiones del programa anterior, ligeramente mejoradas para proporcionar un efecto 3D ms convincente y que el lector pueda comprobar el uso de los mtodos de otras clases. En el primero de estos dos ejemplos se utilizan lneas en vez del rectngulo para crear el efecto de sombra, utilizando lneas dobles para reforzarlo an ms. Adems, se desplaza el texto del botn en el momento en que se pulsa con el ratn, lo cual realza mucho ms el efecto 3D de movimiento del botn. En el otro ejemplo se pinta tambin la parte brillante del botn, adems de las sombras. En ambos, tambin se utiliza un cambio de color del fondo del botn para que el efecto 3D sea mucho ms real de lo que se presentaba en el primer ejemplo de esta seccin.En ese primer ejemplo hay parte del cdigo que merece la pena ser revisado detenidamente, de forma que el lector comprenda ms profundamente su utilizacin. El primer trozo de cdigo en donde hay que detenerse es en el constructor de la clase, que extiende la clase Canvas y sobreescribe el mtodo paint(), adems de definir las variables de instancia que van a controlar el estado del objeto.boolean pulsado = false; // Indica si el botn est pulsado o noint ancho; // Anchura deo botn en pixelsint alto; // Altura del botn en pixelsString rotulo; // Texto del botnLa variable de instancia pulsado es la que se utiliza en el mtodo paint() sobreescrito para determinar la forma en que se va a repintar el botn falso. Se inicializa a false y posteriormente se modifica en el receptor de eventos del ratn. Cuando pulsado es false, el falso botn aparece sobresaliendo de la pantalla, y cuando es true, aparecer como si estuviese hundido en la pantalla.public BotonFalso( int _ancho,int _alto,String _rotulo ) {this.width = _ancho;this.height = _alto;this.caption = _rotulo;this.setBackground( Color.green );this.setSize( this.width,this.height );}El constructor acepta los parmetros que fijan la dimensin del falso botn y el texto que aparecer como su rtulo, y guarda estos parmetros en las variables de instancia de la clase.Lo siguiente en donde hay que detenerse es el mtodo paint(), y lo primero es la parte que pinta el botn en tres dimensiones, que como se puede ver en las siguientes lneas de cdigo es muy simple. Lo primero es comprobar la variable pulsado para determinar qu bordes del rectngulo deben salirse del Canvas; luego se utiliza el mtodo drawRect() para pintar un rectngulo sobre el objeto Canvas con las mismas dimensiones que ese objeto Canvas. Los dos primeros parmetros del mtodo drawRect() especifican las coordenadas de la esquina superior-izquierda del rectngulo en su contenedor; el objeto Canvas, en este caso.public void paint( Graphics g ) {// Determinamos el desplazamiento segn la situacin en que se// encuentre el botn y se pinta el rectngulo sobre el objeto Canvasif( pulsado ) g.drawRect( 1,1,ancho,alto );else g.drawRect( -1,-1,ancho,alto );En el caso de que el botn est pulsado, el rectngulo se desplaza hacia abajo y a la derecha un pixel, de forma que se pierdan las lneas de los bordes derecho e inferior. En el caso de que el botn est normal, es decir, sobresaliendo sobre el Canvas, el rectngulo se desplaza hacia arriba y a la izquierda un pixel, de forma que las lneas que se pierdan sean las correspondientes a los bordes izquierdo y superior.Lo que se hace a continuacin en el mtodo paint() es colocar centrado dentro del objeto, el texto que constituir su rtulo. Como la intencin es colocar ese texto centrado, aproximadamente, las cosas se complican un poco ms que a la hora de pintar el rectngulo. Para posicionar adecuadamente el texto, se utiliza un objeto de tipo FontMetrics, que permite obtener informacin de la fuente de caracteres que est siendo utilizada en un determinado objeto Graphics, invocando a su mtodo getFontMetrics(). Una vez que se tiene el objeto FontMetrics, se puede extraer la informacin necesaria sobre la fuente de caracteres invocando a los mtodos de ese objeto FontMetrics.int altoFuente = g.getFontMetrics().getHeight();int anchoCadena = g.getFontMetrics().stringWidth( rotulo );g.drawString( rotulo,(ancho-anchoCadena)/2,(height/2)+(altoFuente/4) );El posicionamiento horizontal es sencillo, basta con determinar la anchura en pixeles del texto, invocando al mtodo stringWidth() sobre el objeto FontMetrics, pasndole el texto rotulo como parmetro. La ejecucin de este mtodo consume machismo tiempo de CPU, tngalo en cuenta el lector para no abusar en demasa de su utilizacin. Con un poco de aritmtica, es sencillo encontrar la posicin en que se va a colocar el texto.El posicionamiento vertical es un poco ms complicado, ya que el mtodo getHeight() devuelve una combinacin de los parmetros que definen una fuente de caracteres, que son:espaciado, espacio entre lneas

ascendente, tamao de las letras maysculas por encima de la lnea base

descendente, tamao de la parte que queda por debajo de la lnea base, como en el caso de las letras minsculas "g" o "y"

Para hace la programacin sencilla, simplemente se ajusta la lnea base desde la posicin central un poco por debajo del valor devuelto por getHeight(), que para la fuente de caracteres que se utiliza por defecto, parece que 1/4 es un valor que funciona bastante bien.El siguiente cdigo en que hay que detenerse corresponde a las sentencias del constructor del objeto interfaz que instancian los dos objetos de la clase FalsoBoton, que luego son incorporados al objeto Frame utilizando un FlowLayout.// Se instancian dos botones falsos de tamaos diferentes y un botn// real instanciando un objeto de la clase ButtonBotonFalso botFalsoCorto = new BotonFalso( 40,20,"Corto" );BotonFalso botFalsoLargo = new BotonFalso( 80,20,"Largo" );Tambin hay que instanciar un receptor para los eventos del ratn y registrarlo para que reciba los eventos del ratn que se generen sobre los dos falsos botones. Esto se hace en el cdigo que muestran las lneas siguientes.// Receptor de eventos del ratn, que se registra para que reciba los// eventos de ratn que se generen sobre los dos botones falsosProcesoRaton procesoRaton = new ProcesoRaton();botFalsoCorto.addMouseListener( procesoRaton );botFalsoLargo.addMouseListener( procesoRaton );A continuacin, se muestra el cdigo del mtodo sobreescrito mousePressed(), que es invocado cuando se produce un evento de ratn sobre cualquiera de los objetos de tipo BotonFalso. Este mtodo se invoca cuando se pulsa el botn del ratn y hace que el falso botn se hunda sobre la pantalla fijando la variable de instancia del objeto pulsado a true y llamando al mtodo repaint() sobre el objeto. Observe el lector que el objeto de tipo Component devuelto por el mtodo getComponent() debe ser moldeado a la clase BotonFalso, para poder acceder a su variable de instancia pulsado.public void mousePressed( MouseEvent evt ) {// Se fija la variable de que est el botn pulsado y se repinta((BotonFalso)evt.getComponent()).pulsado = true;evt.getComponent().repaint();}Y ya solamente resta ver el cdigo del mtodo mouseReleased(), invocado cuando se suelta el botn del ratn, que es el que hace que el botn falso parezca que vuelve a su posicin normal, sobresaliendo de la pantalla, fijando su variable de instancia pulsado a false y llamando al mtodo repaint() sobre el objeto.public void mouseReleased( MouseEvent evt ) {// Se presenta un mensaje en consola para indicar que el botn se// ha soltadoSystem.out.println( "mouseReleased" );// Se fija la variable de que el botn del ratn se ha liberado y// se repinta el botn sobre el Canvas((BotonFalso)evt.getComponent()).pulsado = false;evt.getComponent().repaint();}En este mtodo tambin se presenta un mensaje por consola para confirmar que el evento se ha producido.Una vez visto por encima y en accin, algunas de las caractersticas de la clase Graphics, llega el momento de detenerse en esta larga y compleja clase. La clase Graphics es la clase base abstracta que proporciona toda, o al menos la mayora, de la funcionalidad para poder pintar tanto sobre componentes como sobre imgenes fuera de pantalla.Un objeto Graphics encapsula la siguiente informacin que ser necesaria a la hora de las operaciones bsicas de pintado.El objeto de tipo Component sobre el que se pinta

Un origen de traslacin para coordenadas de pintado y clipping

La regin actual ocupada por el componente

El color actual

La fuente de caracteres actual

La operacin lgica actual para utilizar con pixeles (XOR o Paint)

La actual alteracin de color XOR

Por lo tanto, lo que sucede cuando se utiliza uno de los mtodos de Graphics para dibujar una lnea o una figura sobre un objeto Component, siguiendo la documentacin de JavaSoft, permite asegurar algunas cosas, tales como las siguientes.Las coordenadas son infinitamente finas y se corresponden con los pixeles del dispositivo de salida.

Las operaciones con dibujo lineal de una figura operan pintando un camino infinitamente pequeo entre los pixeles, con un pincel del tamao fijado desde abajo y a la derecha del punto inicial del camino.

Las operaciones con relleno operan rellenando el interior del camino infinitamente pequeo anterior.

Las operaciones con texto horizontal, pintan la porcin ascendente del carcter completamente sobre las coordenadas de la lnea base.

El hecho de que el pincel grfico se site abajo y a la derecha tiene algunas implicaciones que resultan interesantes.Si se pinta una figura que cubra un rectngulo dado, esa figura ocupar una fila extra de pixeles por al derecha y por abajo, si se compara con una figura rellena con los lmites de ese rectngulo. En el ejemplo java1507.java se observa esta circunstancia, ya que se pinta un rectngulo de las mismas dimensiones que el objeto Canvas que lo contiene, y los bordes derecho e inferior del rectngulo se salen fuera de los lmites del objeto y no son visibles.Otra implicacin es que si se pinta una lnea horizontal a lo largo de la misma coordenada Y como lnea base de un texto, esa lnea se pintar completamente por debajo del texto, excepto en donde los caracteres tengan parte descendente.Cuando se pasan coordenadas a los mtodos de un objeto Graphics, estas coordenadas estn consideradas relativas al origen de traslacin del objeto Graphics que se haya hecho antes de la invocacin al mtodo.Un objeto Graphics describe un contexto grfico. Un contexto grfico define una zona de recorte, una zona a la que va a afectar; cualquier operacin grfica que se realice modificar solamente los pixeles que se encuentren dentro de los lmites de la zona de recorte actual y el componente que fue utilizado para crear el objeto Graphics.Cuando se pinta o escribe, ese dibujo o escritura se realiza en el color actual, utilizando el modo de dibujo actual y la fuente de caracteres actual.Hay muchas otras clases, como la clase Rectangle y la clase Polygon, que utilizan como soporte las operaciones que se pueden realizar con la clase Graphics.Para poder revisar esta clase, quiz una de las mejores formas sea a travs de sus mltiples mtodos, intentando agruparlos por funcionalidad, que es lo que se ha intentado aqu, aunque si el lector quiere una referencia completa y una descripcin de los mtodos de esta clase deber recurrir a la documentacin que JavaSoft proporciona sobre el AWT.Hay que empezar hablando del constructor de la clase Graphics, que no tiene argumentos; aunque Graphics es una clase abstracta, por lo que las aplicaciones no pueden llamar a este constructor directamente. Se puede obtener un objeto de tipo Graphics a partir de otro objeto Graphics llamando al mtodo getGraphics() sobre un componente. Tambin se puede recibir un objeto Graphics como parmetro cuando se van a sobreescribir los mtodos paint() o update().

La clase Graphics, Mtodos Generales

Anterior | Siguiente

En esta categora estaran incluidos los mtodos tiles en general, sin una asignacin especfica de funcionalidad con respecto a acciones determinadas de dibujo. A continuacin se enumeran algunos de los mtodos considerados generales, para seguir con la descripcin y uso de algunos de ellos en aplicaciones de ejemplo.clearRect( int,int,int,int ), se le pasa un rectngulo y borra la zona con el color que se haya establecido de fondo para la superficie donde se est pintando.copyArea( int,int,int,int,int,int ), copia la zona rectangular del componente que se indica en los primeros cuatro parmetros, en otra posicin del contexto grfico desplazada las distancia indicada en los dos ltimos parmetros.create(), crea un nuevo objeto de tipo Graphics que es copia del objeto Graphics que ha invocado al mtodo.dispose(), elimina el contexto grfico sobre el cual es invocado y devuelve al sistema todos los recursos que estaba utilizando, incluyendo todos los recursos, no solamente la memoria. Un objeto Graphics no se puede utilizar despus de haber llamado a este mtodo; y es importante que se eliminen estos objetos manualmente, bien sea creados directamente desde un componente o a partir de otro objeto Graphics, cuando ya no se necesiten, en lugar de esperar a que se finalice la ejecucin.finalice(), elimina el contexto grfico cuando ya no hay ninguna referencia sobre l.getColor(), devuelve el color actual fijado para el contexto grfico.setColor( Color ), fija el color del contexto grfico al color que se pasa como parmetro. Todas las operaciones grfica siguientes que utilicen este contexto grfico, utilizarn el color que se especifica en este mtodo.setPaintMode(), fija la forma de pintar del contexto grfico de modo que se sustituya lo que haba con lo nuevo. Cualquier operacin de pintado sobreescribir lo que hubiese en la zona de destino con el color actual.setXORMode( Color ), fija la forma de pintar del contexto grfico a una alternancia entre en color actual y el color de la zona de destino.toString(), devuelve un objeto de tipo String representando el valor del objeto Graphics.translate( int,int ), traslada el origen del contexto grfico al punto que se pasa en los dos parmetros en el sistema de coordenadas que se est utilizando.Obtener un Contexto GrficoLa verdad es que se han escrito varias veces las palabras contexto grfico, y no se ha proporcionado al lector una explicacin concreta de lo que significan estos trminos. Hay varias definiciones, para unos significa que la aplicacin ha conseguido la habilidad para pintar o colocar imgenes sobre un componente que tiene la caracterstica de soportar el pintado o visualizacin de imgenes. Otros autores prefieren decir que cada objeto Graphics representa una determinada superficie de dibujo, luego ese objeto Graphics define un contexto grfico a travs del cual se pueden manipular todas las actividades grficas sobre esa superficie. Y otros autores indican que un objeto Graphics es la superficie ltima sobre la que se pueden colocar lneas, figuras y texto, por lo cual puede recibir tambin el nombre de contexto grfico al aunar informacin sobre la zona de dibujo, ms la fuente de caracteres, color y cualquier otro factor.Ahora que ya se sabe lo que es un contexto grfico, hay que ver cmo se consigue crear uno. Para empezar, esto no puede hacerse instanciando directamente un objeto de tipo Graphics, ya que la clase Graphics es abstracta y no puede ser instanciada por el cdigo de la aplicacin, as que hay que recurrir a formas indirectas para conseguir el contexto grfico.Uno de estos caminos indirectos para obtener un contexto grfico es invocar el mtodo getGraphics() sobre otro objeto. Sin embargo, este mtodo devuelve un contexto grfico de una imagen, es decir, que solamente funciona para objetos de tipo Image creados en memoria a travs del mtodo createImage(), de la clase Component. Esta es una tcnica utilizada normalmente cuando se estn usando imgenes que se crean en memoria y luego se transfieren a la pantalla, es decir, se est pintando en el doble buffer.Hay otros dos caminos para obtener un contexto grfico y, son sorprendentemente simples, porque se hace automticamente, y es cuando se sobreescriben los mtodos paint() y update(), en los cuales Java pasa como parmetro el contexto grfico del objeto al que pertenece el mtodo.Normalmente, el mtodo paint() se sobreescribe cuando que quiere colocar algn tipo de material grfico sobre la pantalla, y el mtodo update() se sobreescribe en circunstancias especiales, como puede ser el caso de una animacin o que se vaya a utilizar doble buffer. Lo normal es pues la presentacin de informacin grfica colocando el cdigo encargado de ello en el mtodo sobreescrito paint() y luego invocando al mtodo repaint() para indicar al sistema que presente ese material en pantalla; aunque el mtodo paint() tambin puede ser invocado por causas externas, sin control alguno por parte de la aplicacin, como puede se el redimensionamiento de la ventana en la que se est presentando la informacin grfica.Hay que tener en cuenta que el mtodo repaint() pide al sistema que redibuje el componente tan pronto como sea posible, pero esto lo har el mtodo update() que se llame a continuacin. No hay una relacin uno a uno entre las llamadas a repaint() y update(), por lo que es posible que mltiples llamadas a repaint() puedan recogerse en una sola llamada a update().El mtodo update() es invocado automticamente cuando se pide repintar un Componente. Si el componente no es ligero (lightweight), la implementacin por defecto de update() borra el contexto grfico rellenando el fondo en el color que se haya asignado como color de fondo, fijando de nuevo el color al color del primer plano y llamando a paint(). Si no se sobreescribe update() para hacer una animacin, se ver siempre un parpadeo en el refresco del componente por causa de este borrado del fondo.El mtodo paint() es el que ofrece el sistema para poder pintar lo que se quiera sobre un determinado componente. En la case base Component, este mtodo no hace absolutamente nada. Normalmente, en el caso de applets, se sobreescribe para hacer presentar un rectngulo relleno con el color de fondo.El ejemplo java1510.java muestra la forma de utilizar el contexto grfico de forma simple. En el programa, se invoca al mtodo drawString() sobre el contexto grfico de un objeto Frame para presentar las palabras "Tutorial de Java". Si se compila y ejecuta la aplicacin, aparecer el objeto Frame en la pantalla, y en su rea cliente se presentar el texto. Cuando se pulse el botn para cerrar la ventana, desaparecer esa ventana y el control se devolver al sistema operativo.

La imagen anterior corresponde a la ejecucin del programa y su presentacin inicial, y el cdigo completo del programa es el que se reproduce a continuacin.import java.awt.*;import java.awt.event.*;

// Clase de control del ejemploclass java1510 extends Frame {

// Funcin de control de la aplicacinpublic static void main( String[] args ) {// Se instancia un objeto de la clasenew java1510();}

// Contructor de la clasepublic java1510() {this.setTitle( "Tutorial de Java, Grficos" );this.setSize( 300,50 );this.setVisible( true );

// Clase anidada que permite terminar la ejecucin de la animacinthis.addWindowListener(// Definicin de la clase annima para controlar el cierre de// la ventananew WindowAdapter() {public void windowClosing( WindowEvent evt ) {// Se concluye el programaSystem.exit( 0 );}} );}

// Se sobrecarga el mtodo paint(), para presentar una cadena de// texto en la ventana que se abre en pantalla, sobre el contexto// grfico del objeto Framepublic void paint( Graphics g ) {g.drawString( "Tutorial de Java",100,40 );}}La nica parte interesante del cdigo de este ejemplo, desde el punto de vista grfico, es el mtodo sobreescrito paint() que permite pintar las palabras sobre el contexto grfico que se le pasa como parmetro, tal como se ve en las siguientes lneas.public void paint( Graphics g ) {g.drawString( "Tutorial de Java",100,40 );}El resto del cdigo del ejemplo no merece la pena revisarlo, porque es semejante al que aparece otros muchos programas de ejemplo que se presentan en el Tutorial.Crear un Contexto GrficoEl mtodo create() crea un nuevo objeto Graphics que es una copia del objeto Graphics sobre el cual es invocado. Quiz sea ms adecuado decir que se crea una segunda referencia al objeto Graphics sobre el cual es invocado el mtodo, porque cualquier cosa que se pinte utilizando la nueva referencia, aparecern sobre el contexto grfico original cuando se repinte.Aunque en esta seccin de lo que se trata es de presentar el uso del mtodo create(), lo cierto es que todo se encuentra implicado. A travs de los ejemplos, el lector comprobar que se van introduciendo otra serie de conceptos, como en este caso es el uso de insets a la hora de pintar un objeto que tiene borde, como es un objeto de tipo Frame, el uso de clipping, el uso de setColor() para cambiar el color con que se pinta o el uso del mtodo dispose() para devolver los recursos utilizados por el contexto grfico al sistema operativo. Por ello, el lector no debe abrumarse, ya que aunque se introduzcan muchos conceptos, siempre se intentar dar a cada uno de ellos su autntica relevancia, aunque sea en secciones diferentes.El ejemplo que se presenta a continuacin, java1511.java, resuelve el problema asociado con insets, aadiendo valores para compensarlo a las coordenadas que se pasan como parmetros en las invocaciones de los mtodos. El ejemplo java1512.java, lo resuelve de forma distinta, superponiendo sobre el objeto Frame un objeto Canvas, que no tiene insets. Posteriormente, el lector podr comprobar que el problema de insets tambin se eliminar con el uso del mtodo translate().Pero antes de seguir, un comentario sobre el uso del mtodo dispose(), porque hay autores que ofrecen explicaciones diferentes sobre la necesidad de eliminar el contexto grfico que se crea. Quiz lo mejor sea aceptar la documentacin que proporciona JavaSoft, que dice que el mtodo dispose() se encarga de eliminar el contexto grfico y devolver al sistema todos los recursos que estuviese utilizando, de forma que un objeto Graphics nunca puede ser llamado despus de haber invocado a su mtodo dispose().Cuando se ejecuta un programa Java, un gran nmero de objetos de tipo Graphics son creados con muy poco intervalo de tiempo; aunque al finalizar el proceso, el recolector de basura, garbage collector, es capaz de liberar esos mismos recursos, es preferible liberar manualmente los recursos asociados a los objetos Graphics llamando a dispose() en lugar de esperar a la finalizacin del proceso, que puede estar muy dilatada en el tiempo.Los recursos asociados a los objetos Graphics que se pasan como argumentos a los mtodos paint() y update() de los componentes, son automticamente liberados por el sistema cuando finaliza la ejecucin del mtodo. Por eficiencia, los programadores deberan incluir una llamada a dispose() cuando no van a utilizar un objeto Graphics solamente si ese objeto fue creado directamente desde un componente o a partir de otro objeto Graphics.En el ejemplo java1511.java, se ilustra el uso de clipping, color, rectngulos, lneas, insets y dispose(), realizando todas las acciones en el mtodo sobreeescrito paint().Cuando se compila y ejecuta este programa, en pantalla aparece u objeto Frame, con un rectngulo rojo en su interior, colocado a partir de la esquina superior-izquierda del Frame. Atravesando a este rectngulo hay una lnea azul, que a su vez est atravesada por una lnea verde, que cruza el rectngulo en sentido contrario, de la cual solamente se visualiza la parte central, ya que es el resultado de la accin de recorte (clipping) que se ha aplicado a la segunda referencia del objeto. La imagen siguiente corresponde a la captura de la ventana generada durante la ejecucin del ejemplo, en la que se pueden comprobar esos detalles.

El listado que se muestra a continuacin, correspondiente al ejemplo, muestra en sus comentarios todas las acciones que se van llevando a cabo para la generacin del grfico.import java.awt.*;import java.awt.event.*;

// Clase de control del ejemploclass java1511 extends Frame {

// Funcin de control de la aplicacinpublic static void main( String[] args ) {// Se instancia un objeto de la clasenew java1511();}

// Contructor de la clasepublic java1511() { this.setTitle( "Tutorial de Java, Grficos" );this.setSize( 300,150 );this.setVisible( true );

// Clase anidada que permite terminar la ejecucin de la animacinthis.addWindowListener(// Definicin de la clase annima para controlar el cierre de// la ventananew WindowAdapter() {public void windowClosing( WindowEvent evt ) {// Se concluye el programaSystem.exit( 0 );}} );}

// Se sobrecarga el mtodo paint()public void paint( Graphics g ) {// Obtenemos el tamao de los insets para tenerlos en cuentaint arr = this.getInsets().top;int izq = this.getInsets().left;// Fijamos el color rojo para pintarg.setColor( Color.red );

// Creamos una segunda referencia del contexto grfico que se // utiliza en el mtodoGraphics clpArea = g.create();// Usamos esta referencia para pintar un rectngulo rojoclpArea.drawRect( 0+izq,0+arr,250,100 );

// Se redude el rectngulo de clipping, de forma que solamente se// quede sin recortar un rectngulo ms pequeo clpArea.clipRect( 25+izq,25+arr,200,50 );

// Se usa el contexto para pintar una lnea diagonal verde a lo largo// del rectngulo original, aunque por la accin de la zona de// clipping que se ha fijado antes, solamente estar visible la// parte central clpArea.setColor( Color.green );clpArea.drawLine( 0+izq,0+arr,250+izq,100+arr );

// Liberamos los recursos usados por el contexto grficoclpArea.dispose();// Y lo seleccionamos como candidato a la basuraclpArea = null;

// Ahora usamos el contexto grfico original para pintar una// lnea azul que atraviesa todo el rectngulo, y que ya no// se ve afectada por el rectngulo de recorte que se haba fijado// en la segunda referencia del contexto que habamos creado antes g.setColor( Color.blue );g.drawLine( 0+izq,100+arr,250+izq,0+arr );}}El ejemplo anterior presentaba el problema ocasionado por insets. En el ejemplo java1512.java, se utiliza un objeto de tipo Canvas como superficie de dibujo, para evitar este problema, ya que un objeto Canvas no tiene bordes.El problema que ocasiona insets, se debe al hecho de que algunos contenedores, como lo es un objeto Frame, tienen bordes, y el rea ocupada por estos bordes es considerada como parte de la zona de dibujo, de modo que las coordenadas del punto 0,0 corresponden a la esquina superior-izquierda del contenedor, oculta por los bordes, en caso de que ese contenedor tenga bordes.El mtodo getInsets() proporciona el ancho el pixeles de los cuatro bordes, lo cual hace posible que se compense matemticamente la influencia de esos bordes cuando se trabaje con valores de coordenadas.Para poder utiliza un objeto Canvas como superficie de dibujo, es necesario extender la clase Canvas para poder sobreescribir su mtodo paint(). En este programa, la clase Canvas se extiende en la clase MiClase, que es donde se sobreescribe el mtodo paint() para poder realizar operaciones grficas. Se instancia un objeto de tipo MiCanvas, que se aade al objeto Frame y acta como zona de dibujo superpuesta a este objeto Frame. Como el objeto MiCanvas no tiene bordes, el problema insets est eliminado.import java.awt.*;import java.awt.event.*;

// Clase para crear la zona de dibujo, que extiende a la clase Canvas// para que sea posible sobrecargar el mtodo paint()class MiCanvas extends Canvas {// Se sobrecarga el mtodo paint()public void paint( Graphics g ) {// Fijamos el color rojo para pintarg.setColor( Color.red );

// Creamos una segunda referencia del contexto grfico que se // utiliza en el mtodoGraphics clpArea = g.create();// Usamos esta referencia para pintar un rectngulo rojoclpArea.drawRect( 0,0,250,100 );

// Se redude el rectngulo de clipping, de forma que solamente se// quede sin recortar un rectngulo ms pequeo clpArea.clipRect( 25,25,200,50 );

// Se usa el contexto para pintar una lnea diagonal verde a lo largo// del rectngulo original, aunque por la accin de la zona de// clipping que se ha fijado antes, solamente estar visible la// parte central clpArea.setColor( Color.green );clpArea.drawLine( 0,0,250,100 );

// Liberamos los recursos usados por el contexto grficoclpArea.dispose();// Y lo seleccionamos como candidato a la basura clpArea = null;

// Ahora usamos el contexto grfico original para pintar una// lnea azul que atraviesa todo el rectngulo, y que ya no// se ve afectada por el rectngulo de recorte que se haba fijado// en la segunda referencia del contexto que habamos creado antes g.setColor( Color.blue );g.drawLine( 0,100,250,0 );}}

// Clase de control del ejemploclass java1512 extends Frame {

// Funcin de control de la aplicacinpublic static void main( String[] args ) {// Se instancia un objeto de la clasenew java1512();}

// Contructor de la clasepublic java1512() { this.setTitle( "Tutorial de Java, Grficos" );this.setSize( 300,150 );

// Se crea una superficie amarilla y se utiliza para cubrir el// rea cliente del objeto FrameMiCanvas zonaDibujo = new MiCanvas();zonaDibujo.setBackground( Color.yellow );this.add( zonaDibujo );this.setVisible( true );

// Clase anidada que permite terminar la ejecucin de la animacinthis.addWindowListener(// Definicin de la clase annima para controlar el cierre de// la ventananew WindowAdapter() {public void windowClosing( WindowEvent evt ) {// Se concluye el programaSystem.exit( 0 );}} );}}El listado anterior no necesita ningn comentario adicional a los que ya se encuentran insertados en el cdigo, que el lector puede seguir para ver las acciones que se llevan a cabo.Copiar y BorrarLos dos mtodos involucrados en estas acciones son copyArea() y clearRect(). El segundo es el ms sencillo y su funcin es borrar el rectngulo determinado por los cuatro parmetros que se le pasan, rellenndolo con el color de fondo de la superficie de dibujo.Los parmetros que admite son: x, y, ancho, alto. Siendo x e y, como en casi todos los mtodos grficos en Java, las coordenadas referidas a la esquina superior-izquierda de la zona rectangular que se quiere borrar, y ancho y alto, las dimensiones de esa misma zona rectangular.El mtodo copyArea() copia una zona rectangular de la superficie actual de dibujo a otra zona que se encuentra separada de la primera por una distancia especificada en los parmetros adicionales dx y dy. La zona se copia desplazando hacia abajo y a la derecha, si se quiere copiar hacia arriba o hacia la izquierda hay que proporcionar valores negativos en dx o en dy. Cualquier parte del rectngulo origen que se salga de la superficie de dibujo no se copiar.En el ejemplo java1513.java se ilustra el uso de estos mtodos. El programa pinta la cadena de texto "Tutorial de Java" en la esquina superior izquierda de un objeto Frame. Luego, utiliza el mtodo copyArea() para hacer dos copias adicionales de esa zona, copiando un rea rectangular a partir de la esquina superior-izquierda en otras dos reas. Y despus utiliza el mtodo clearRect() para borrar la mayor parte de la letra "T" de la segunda copia, borrando una zona rectangular de la pantalla que contiene a la letra "T".

La imagen anterior es el resultado que se observa en pantalla cuando se ejecuta el ejemplo, en donde se pueden observar las dos copias del texto, con la letra "T" casi desaparecida en la segunda de ellas. El listado completo del ejemplo es el que se reproduce a continuacin.import java.awt.*;import java.awt.event.*;

// Clase de control del ejemploclass java1513 extends Frame {

// Funcin de control de la aplicacinpublic static void main( String[] args ) {// Se instancia un objeto de la clasenew java1513();}

// Contructor de la clasepublic java1513() {this.setTitle( "Tutorial de Java, Grficos" );this.setSize( 300,100 );this.setVisible( true );

// Clase anidada que permite terminar la ejecucin de la animacinthis.addWindowListener(// Definicin de la clase annima para controlar el cierre de// la ventananew WindowAdapter() {public void windowClosing( WindowEvent evt ) {// Se concluye el programaSystem.exit( 0 );}} );}

// Se sobrecarga el mtodo paint(), para presentar una cadena de// texto en la ventana que se abre en pantalla, sobre el contexto// grfico del objeto Framepublic void paint( Graphics g ) {g.drawString( "Tutorial de Java",10,40 );// Se copia la zona ocupada por la cadenag.copyArea( 0,0,100,100,100,0 ); // Se hace otra copiag.copyArea( 0,0,100,100,100,40 );// Se borra parte de esta segunda copiag.clearRect( 100,40,15,40 );}}Traslacin del OrigenEl mtodo translate() se utiliza para trasladar el origen del contexto grfico al punto de coordenada que se pasa como parmetro al mtodo. El mtodo modifica el contexto grfico de forma que el origen del sistema de coordenadas que se utilice en ese contexto grfico corresponda al punto especificado. Todas las coordenadas utilizadas en posteriores operaciones grficas sobre ese contexto grfico, sern relativas al nuevo origen.El uso de este mtodo es otra forma de eliminar el problema originado por la anchura de los bordes colocados sobre la zona de dibujo, insets. En particular, el mtodo se puede utilizar para trasladar el origen del contexto grfico a la esquina superior-izquierda de la zona cliente del objeto Frame, por la parte interna de los bordes.El ejemplo java1514.java, replica la funcionalidad del ejemplo java1511.java, pero elimina el problema de insets invocando al mtodo translate() sobre el contexto grfico original para desplazar el origen de coordenadas a la parte interna de los bordes.Los cambios a realizar al ejemplo java1511.java son mnimos, limitndose casi exclusivamente a la incorporacin de la llamada al mtodo translate(), para implementar esta nueva solucin al problema de insets.// Trasladamos el origen de coordenadas que se sita en la// esquina superior izquierda, para evitar el problema que se// produce con insets. De este modo el origen de coordenadas s// que lo dejamos situado en la zona cliente del objeto Frame // que es la que se utiliza para pintasg.translate( this.getInsets().left,this.getInsets().top );Pintar Normal y XORLa verdad es que a la hora de plantear esta seccin, surge la duda de si ser til o no al lector. Como en todas las ocasiones, s ser til para unos y nunca lo ser para otros, por eso que si el lector sabe que va a realizar dibujos en modo XOR (OR Exclusivo), pues lo ms lgico es que no necesite pintar en modo XOR. No obstante, y como aclaracin, aqu se intenta explicar "cmo se hace" no el "porqu hacerlo", ya que ser el lector el que determine si de verdad necesita utilizar esta tcnica o no.El modo de pintar Normal que resulta despus de invocar al mtodo setPaintMode() es fcil de explicar. Cada nuevo pixel que se pinte reemplazar al existente con el color de ese nuevo pixel. Sin embargo, el modo de pintar XOR que resulta de invocar al mtodo setXORMode() resulta mucho ms complejo y requiere un poco de explicacin.Las reglas para determinar el resultado de una operacin OR exclusive entre dos bits, son las que se muestran a continuacin0 xor 0 = 01 xor 0 = 10 xor 1 = 11 xor 1 = 0

En otras palabras, si los dos bits son iguales la salida es un 0, en caso contrario es un 1.La siguiente tabla muestra el patrn de 24 bits correspondiente a cuatro colores de la paleta que utiliza Java.111111110000000000000000 = rojo000000001111111100000000 = verde000000000000000011111111 = azul111111111111111111111111 = blanco

Cuando se invoca al mtodo setXORMode( Color otroColor ), el color de cada pixel estar determinado por la operacin XOR realizada entre los valores del color actual de dibujo, el valor de la variable otroColor pasada como parmetro al mtodo y el color actual del pixel. Por ejemplo, la operacin XOR entre un nuevo pixel rojo sobre un pixel ya existente de color rojo donde se llama al mtodo setXORMode() pasndole el color verde como parmetro, dara como resultado un pixel de color verde, tal como se puede comprobar en la tabla siguiente en donde se muestra la operacin realizada.111111110000000000000000 = rojo111111110000000000000000 = rojo000000000000000000000000 = resultado intermedio000000001111111100000000 = verde000000001111111100000000 = resultado final (verde)

Como se puede ver, la operacin XOR entre color rojo y color rojo, genera el valor del color que va a realizar la operacin con el color que se pasa al mtodo setXORMode(). De este modo, si se est pintando en modo XOR y dibujando rojo sobre rojo, el resultado ser en realidad el color que se pasa como parmetro al mtodo, y esto ser verdad para cualquier color que se superponga sobre pixeles del mismo color.Si ahora se considera un nuevo ejemplo XOR en que se pinte un pixel rojo sobre un pixel blanco y se utilice el color verde como parmetro del mtodo setXORMode(), el resultado final ya no es tan predecible, tal como se ve en el desglose de las operaciones.111111110000000000000000 = rojo111111111111111111111111 = blanco000000001111111111111111 = resultado intermedio000000001111111100000000 = verde000000000000000011111111 = resultado final (azul)

En este caso, la operacin XOR entre los colores rojo, blanco y verde genera el color azul. Utilizando este esquema, el lector sera capaz de determinar el valor numrico del color final que se producir en la operacin XOR de cualquier tripleta de colores.Una de las razones para utilizar el dibujo en XOR es el hecho de que una figura se redibuje a s misma en modo XOR, siendo el resultado final la desaparicin de la figura quedando en imagen el color de fondo, o la imagen de fondo, que hubiese originalmente. Y esto es as incluso en fondos multicolores, de tal modo que a veces es una de las tcnicas utilizadas en animacin para pintar y borrar una figura muy rpidamente. Con estos conceptos en mente, considere el lector el hecho de realizar la misma operacin XOR dos veces seguidas, por ejemplo, en el primero de los casos, en que se utilizaban los colores rojo, rojo y verde. Las operaciones seran las que muestra la tabla.111111110000000000000000 = rojo111111110000000000000000 = rojo000000000000000000000000 = resultado intermedio000000001111111100000000 = verde000000001111111100000000 = resultado final (verde)

ahora se hace lo mismo, pero se comienza con el color verde000000001111111100000000 = verde111111110000000000000000 = rojo000000000000000000000000 = resultado intermedio000000001111111100000000 = verde111111110000000000000000 = rojo, el valor original del pixel

Como era de esperar, el resultado final es el valor original del color que tena el pixel, tras realizar las dos operaciones XOR seguidas.El ejemplo java1515.java muestra el resultado de la utilizacin de los dos modos de dibujo, setXORMode() y setPaintMode(), y el redibujo de la imagen original.En este caso s que es importante que el lector observe la imagen en la que se reproduce la ventana generada por la ejecucin del programa, ya que es imprescindible para entender la descripcin que sigue.

En la ventana aparecen dos grupos de cuatro cuadrados que se superponen parcialmente, utilizando el color rojo como color de dibujo, que no se cambia en toda la secuencia de pintado.En los dos grupos de cuadrados, los dos primeros se pintan en modo Paint, de forma que simplemente se mezclan. Excepto porque este autor afirma que realmente son cuadrados, el lector con la simple visin de la imagen no sera capaz de asegurar tal cosa; por ejemplo, si en vez de cuadrados se utilizasen polgonos, s que sera muy difcil al lector discernir la figura que resultase del solapamiento de esos polgonos.Luego se cambia a modo XOR con el color verde como parmetro, pintando un tercer cuadrado con el color rojo de dibujo sin alterar. En este caso, la zona de solapamiento entre los dos cuadrados es verde, como bien habra adivinado el lector en base a la discusin lgica mantenida anteriormente, y esa zona destaca perfectamente. Y la zona que no solapa al cuadrado anterior, como tiene el color blanco de fondo, se pintar en azul, confirmando de nuevo la discusin lgica anterior.Ahora se vuelve a cambiar el modo a Paint para pintar el cuarto cuadrado, que por supuesto, se superpone sobre todo, incluso sobre la zona azul del cuadrado anterior.En el grupo de cuadrados de la derecha, se realiza la misma secuencia, pero una vez pintados los cuatro cuadrados, se vuelve a fijar el modo XOR y se pinta un ltimo cuadrado sobre la posicin del tercero de ellos, que se haba pintado en modo XOR; es decir, el tercer cuadrado se redibuja en modo XOR. Esto hace que las partes de colores verde y azul se vuelvan de color rojo y blanco, respectivamente, eliminando el cuadrado y devolviendo a la figura sus colores originales, tal como se podra prever.Sin embargo, est la porcin de este tercer cuadrado que ahora solapa al que previamente se haba pintado en cuarta posicin, que aparecer en color verde, porque el cuarto cuadrado no estaba ah en el momento en que se pint el tercer cuadrado, luego originalmente el color de esa zona era azul, no rojo.El listado del ejemplo est profuso en comentarios, para que el lector pueda seguir fcilmente la secuencia en que se realizan las operaciones descritas anteriormente, que dan origen a la imagen de la ventana que se ha comentado.import java.text.*;import java.util.*;import java.awt.*;import java.awt.event.*;

// Clase de control del ejemploclass java1515 extends Frame { // Funcin de control de la aplicacinpublic static void main( String[] args ) {// Se instancia un objeto de la clasenew java1515();}

// Contructor de la clasepublic java1515() { this.setTitle( "Tutorial de Java, Grficos" );this.setSize( 300,150 );this.setVisible( true );

// Clase anidada que permite terminar la ejecucin de la animacinthis.addWindowListener(// Definicin de la clase annima para controlar el cierre de// la ventananew WindowAdapter() {public void windowClosing( WindowEvent evt ) {// Se concluye el programaSystem.exit( 0 );}} );}

// Se sobrecarga el mtodo paint()public void paint(Graphics g){g.setColor(Color.red);

// Trasladamos el origen de coordenadas que se sita en la// esquina superior izquierda, para evitar el problema que se// produce con insets. De este modo el origen de coordenadas s// que lo dejamos situado en la zona cliente del objeto Frame // que es la que se utiliza para pintasg.translate( this.getInsets().left,this.getInsets().top );

// Se pinta un primer grupo de cuadrados rojos, rellenos, en el// mtodo Paint, que es el que se utiliza por defectog.fillRect( 0,0,50,50 );g.fillRect( 25,25,50,50 );// Se cambia el modo de pintar a XOR y se pinta un nuevo cuadrado// en color rojo con el color XOR puesto a verde. Esto hara que// aparezca un cuadrado verde donde se superpone con el rojo de// los cuadrados anteriores y azul en el resto, ya que se est// superponiendo al color blanco del fondo de la ventanag.setXORMode( Color.green );g.fillRect( 50,50,50,50 );// Cambiamos otra vez a modo Paint, para pintar un nuevo cuadrado// rojo que tapar parte de la zona azul del cuadrado anterior y// ser rojo en el restog.setPaintMode();g.fillRect( 75,75,50,50 );

// Ahora se muestra la cancelacin del efecto de redibujado de// un cuadrado en modo ZOR. Se pinta un segundo conjunto de// cuadrados a la derecha del anterior, rellenndolos siguiendo// la misma secuencia que se ha seguido para el grupo anterior g.fillRect( 150,0,50,50 );g.fillRect( 175,25,50,50 );g.setXORMode( Color.green );g.fillRect( 200,50,50,50 );g.setPaintMode();g.fillRect( 225,75,50,50 );

// Ahora, y esto es lo importante, redibujamos el tercer cuadrado// de este segundo conjunto en modo XOR. Esto borrar el que// estaba anteriormente , excepto donde se superpona sobre el// cuarto cuadrado, en donde la zona de solape ser verdeg.setXORMode( Color.green );g.fillRect( 200,50,50,50 );}}

La clase Graphics, Mtodos para pintar Figuras

Anterior | Siguiente

Aqu se refieren los mtodos destinados al dibujo de lneas, polilneas, figuras geomtricas, etc. tanto en las versiones lineales como en su correspondiente rellena. Algunos de estos mtodos son los que se citan a continuacin.drawLine( int,int,int,int ), pinta una lnea, utilizando el color actual, ente dos puntos del sistema de coordenadas del contexto grfico.drawPolyline( int[],int[],int ), pinta una secuencia de lneas conectadas, definidas por conjuntos de coordenadas x e y. La figura resultante no estar cerrada si el primer punto es diferente al ltimo.drawRect( int,int,int,int ), pinta una lnea delimitando el rectngulo especificado por las esquinas indicadas en las coordenadas que se pasan utilizando el color actual del contexto grfico.fillRect( int,int,int,int ), rellena el rectngulo especificado con el color actual. Tenga en cuenta el lector que los lados izquierdo y derecho del rectngulo son x y x+ancho-1, y que los lados superior e inferior son y e y+alto-1; esto es as en todos los mtodos en donde se rellenen figuras.drawRoundRect( int,int,int,int,int,int ), pinta una lnea delimitando el rectngulo especificado, con las esquinas redondeadas, con el color actual. Los dos ltimos parmetros corresponden a las dimensiones de los dimetros horizontal y vertical del arco que sirve para redondear las cuatro esquinas del rectngulo. fillRoundRect( int,int,int,int,int,int ), rellena el rectngulo redondeado que se indica con el colora actual.draw3DRect( int,int,int,int,boolean ), pinta un rectngulo con los bordes iluminados para dar sensacin 3D, de forma que parezca que se el rectngulo se encuentra en un plano diferente al plano normal de dibujo. El ltimo parmetro indica si se iluminan unos bordes u otros para dar la sensacin de que el rectngulo sobresale o est hundido.fill3DRect( int,int,int,int,boolean ), pinta un rectngulo 3D relleno con el color actualdrawOval( int,int,int,int ), pinta una elipse en el color actual. Si los dos ltimos parmetros son iguales, el resultado ser un crculo.fillOval( int,int,int,int ), pinta un crculo relleno con el color actual, delimitado por el rectngulo constituido por los parmetros que se pasan.drawArc( int,int,int,int,int,int ), pinta una lnea de un arco circula o elptico. El lector debera consultar la documentacin oficial del mtodo para saber exactamente cmo especificar los parmetros.fillArc( int,int,int,int,int,int ), rellena un arco circular o elptico delimitado por el rectngulo que se indica.drawPolygon( Polygon ), pinta un polgono definido por el objeto Polygon que se para como parmetro. La clase Polygon encapsula la descripcin de una zona, dentro del espacio de coordenadas, delimitada por un nmero arbitrario de segmentos lineales, cada uno de los cuales corresponde a uno de los lados del polgono. Internamente, un polgono consta de una lista de pares de coordenadas (x,y), donde cada uno de esos pares define un vrtice del polgono y cada dos pares consecutivos defines un lado del polgono. Los vrtices inicial y final se unen automticamente formando otro de los lados del polgono.fillPolygon( Polygon ), rellena el polgono especificado por el objeto Polygon con el color actual que se haya fijado para el contexto grfico. Tanto para este mtodo como para el anterior, drawPolygon(), hay una versin sobrecargada que admite una lista de coordenadas para especificar el polgono.De todos los mtodos, quizs el ms complejo sea drawArc(), por la forma en que hay que pasar los parmetros y el significado de stos; el resto de los mtodos no reviste dificultad alguna en su uso. Cada uno de los mtodos que nos permiten representar en pantalla elipses y arcos, requieren como parmetros las coordenadas del punto central del valo o arco y el ancho y alto, en valor positivo, del rectngulo que circunscribe a ese valo o arco. Para pintar arcos, es necesario proporcionar dos parmetros adicionales, un ngulo de inicio y un ngulo para el arco; de este modo se especifica el inicio del arco y en tamao del arco en grados (no en radianes). En la figura que sigue se indica cmo se tiene en cuenta el ngulo a la hora de las especificacin de ngulos en los valores de los parmetros a pasar a los mtodos drawArc() y fillArc().

El ejemplo java1516.java muestra ejemplos de todas las figuras que se pueden generar con los mtodos que se acaban de enumerar. Si el lector compila y ejecuta el programa, ver una imagen semejante a la que presenta la figura siguiente.

El cdigo completo del ejemplo es el que se reproduce a continuacin, en el cual el lector puede comprobar los parmetros que se pasan a cada uno de los mtodos para generar las figuras que se muestran en la imagen anterior.import java.awt.*;import java.awt.event.*;

// Clase de control del ejemploclass java1516 extends Frame {

// Funcin de control de la aplicacinpublic static void main( String[] args ) {// Se instancia un objeto de la clasenew java1516();}

// Contructor de la clasepublic java1516() {this.setTitle( "Tutorial de Java, Grficos" );this.setSize( 475,275 );this.setVisible( true );

// Clase anidada que permite terminar la ejecucin de la animacinthis.addWindowListener(// Definicin de la clase annima para controlar el cierre de// la ventananew WindowAdapter() {public void windowClosing( WindowEvent evt ) {// Se concluye el programaSystem.exit( 0 );}} );}

// Se sobrecarga el mtodo paint()public void paint( Graphics g ){g.setColor( Color.red );

// Trasladamos el origen de coordenadas que se sita en la// esquina superior izquierda, para evitar el problema que se// produce con insets. De este modo el origen de coordenadas s// que lo dejamos situado en la zona cliente del objeto Frame // que es la que se utiliza para pintasg.translate( this.getInsets().left,this.getInsets().top );

// Lnea simpleg.drawLine( 10,0,50,50 );g.setColor( Color.black );g.drawString( "drawLine",10,62 );g.setColor( Color.red );

// Se crean dos arrays de coordenadas para pintar una // polilneaint x1Datos[] = {80,130,80,130}; int y1Datos[] = {0,50,50,0};g.drawPolyline( x1Datos,y1Datos,4 );g.setColor( Color.black );g.drawString( "drawPolyline",70,62 );g.setColor( Color.red );

// Rectngulog.drawRect( 150,0,50,50 );g.setColor( Color.black );g.drawString( "drawRect",150,62 );g.setColor( Color.red );

// Rectngulo rellenog.fillRect( 220,0,50,50 );g.setColor( Color.black );g.drawString( "fillRect",225,62 );g.setColor( Color.red );

// Rectngulo redondeadog.drawRoundRect( 300,0,50,50,10,10 );g.setColor( Color.black );g.drawString( "drawRoundRect",280,62 );g.setColor( Color.red );

// Rectngulo redondeado rellenog.fillRoundRect( 385,0,50,50,10,10 );g.setColor( Color.black );g.drawString( "fillRoundRect",375,62 );

// Pinta un rectngulo 3D, sobresaliendo de la pantalla// No parece demasiado 3Dg.setColor( Color.gray );//draw the 3D stuff in grayg.draw3DRect( 10,90,55,25,true );// Rectngulo 3D, pulsadog.draw3DRect( 70,90,50,25,false );g.setColor( Color.black );g.drawString( "draw3DRect",30,140 );

// Rectngulo 3D relleno. Se ha puesto un fondo gris// con lo cual se puede apreciar mucho mejor el efecto// de tres dimensiones// Fondo grisg.setColor( Color.gray );g.fillRect( 145,75,130,55 );g.fill3DRect( 155,90,50,25,true );// Rectngulo 3D relleno, pulsadog.fill3DRect( 215,90,50,25,false );g.setColor( Color.red );// De todos modos, la apariencia de tres dimensiones// con 3DRect no es demasiado buena, porque es necesario// seleccionar muy bien la paleta de colores para que// se genere la ilusin de 3Dg.setColor( Color.black );g.drawString( "fill3DRect",180,140 );g.setColor( Color.red );

// Pinta un ngulo de 255 grados inscrito en un rectngulo g.drawRect( 300,77,50,50 );g.drawArc( 300,77,50,50,0,225 ); g.setColor( Color.black );g.drawString( "drawArc",305,140 );g.setColor( Color.red );

// Angulo relleno de 255 grados inscrito en un rectngulo g.drawRect( 385,77,50,50 );g.fillArc( 385,77,50,50,0,225 );g.setColor( Color.black );g.drawString( "fillArc",395,140 );g.setColor( Color.red );

// Elipse, con el eje grande horizontalg.drawOval( 10,165,50,25 );// Crculog.drawOval( 70,150,50,50 );g.setColor( Color.black );g.drawString( "drawOval",35,218 );g.setColor( Color.red );

// Elipse rellena, con el eje grande verticalg.fillOval( 170,150,25,50 );// Crculo rellenog.fillOval( 210,150,50,50 ); g.setColor( Color.black );g.drawString( "fillOval",185,218 );g.setColor( Color.red );

// Polgonoint x2Datos[] = {300,350,300,350};int y2Datos[] = {150,200,200,150}; g.drawPolygon( x2Datos,y2Datos,4 );g.setColor( Color.black );g.drawString( "drawPolygon",290,218 );g.setColor( Color.red );

// Polgono rellenoint x3Datos[] = {385,435,385,435};int y3Datos[] = {150,200,200,150}; g.fillPolygon( x3Datos,y3Datos,4 );g.setColor( Color.black );g.drawString( "fillPolygon",385,218 );}}Quizs merezca la pena un repaso de los mtodos draw3Drect() y fill3Drect(), que son los encargados de pintar rectngulos que aparezcan en pantalla dando sensacin de ests flotando sobre ella o hundidos. Este efecto visual se consigue mostrando dos de los lados en un color ms claro que los otros dos, ofreciendo al ojo humano la ilusin de que los bordes ms claros estn iluminados y los ms oscuros son producto de las sombras. Esto puede ser til en ocasiones, pero hay otras en que en modo alguno se consigue el efecto; si el color de fondo del contenedor sobre el que se va a colocar el rectngulo 3D, tiene un color cercano al color de ese rectngulo, entonces el efecto est conseguido, pero si se intenta colocar un rectngulo relleno con color rojo sobre un fondo blanco, el efecto pasa desapercibido.

La clase Graphics, Mtodos para pintar Texto

Anterior | Siguiente

La clase Graphics dispone de mtodos para pintar texto, aunque tambin proporciona mtodos para devolver informacin sobre el texto y sobre la fuente de caracteres que se est utilizando para presentarlo en pantalla. Un resumen de estos mtodos es lo que se presenta a continuacin.drawString( String,int,int ), pinta el texto indicado en la cadena, en la posicin indicada en los parmetros que corresponden a la coordenada donde se colocar el primer carcter de la cadena, utilizando el color actual y la fuente de caracteres actual.drawChars( char[],int,int,int ), pinta el texto indicado en el array de caracteres, utilizando el color y fuente de caracteres actuales del contexto grfico. Hay otra versin que permite pasar un array de bytes para representar los caracteres que se van a pintar.getFont(), coge la fuente de caracteres actual y devuelve un objeto de tipo Font que describe esa fuente de caracteres.getFontMetrics(), coge los parmetros de la fuente actual y devuelve un objeto de tipo FontMetrics. Los mtodos de la clase FontMetrics permiten obtener informacin sobre los parmetros de la fuente de caracteres (tamao, etc.) a la que se aplica el mtodo getFontMetrics().getFontMetrics( Font ), devuelve la informacin de la fuente indicada en el parmetro de llamada al mtodo.setFont( Font ), fija la fuente actual del contexto grfico a la que se indica en el parmetro de llamada.Al igual que ocurre en cualquiera de los apartados de la programacin en Java, las lista anterior solamente proporciona los mtodos que permiten el control, pero el poder real se encuentra examinando detenidamente los mtodos y las clases de los objetos que devuelven esos mtodos, porque a la hora de pintar un texto, hay al menos cuatro clases implicadas. La primera es la clase String, de la que se trata profundamente en otra seccin y no se va a insistir aqu, y las dems clases son FontMetrics y Font, de las cuales se proporciona una pequea descripcin en los prrafos siguientes. Tenga en cuenta el lector, que esta es una descripcin muy somera y que estas clases son realmente potentes, proporcionando una flexibilidad casi absoluta a la hora de pintar texto en pantalla.Las coordenadas que se indican para posicionar el texto, corresponden al punto correspondiente a la esquina inferior izquierda del texto, aunque no exactamente. En realidad, la coordenada y indica dnde est la lnea base del texto, que no contempla el desplazamiento por debajo de esa lnea de caracteres con imagen descendente, como la letra "g". Por ello, hay que asegurarse de especificar en la coordenada y un valor suficiente para permitir el pintado del carcter completo, porque en caso contrario, la parte descendente de los caracteres con esta caracterstica no se visualizara.La clase FontUna fuente de caracteres es un conjunto de caracteres de un tipo y un tamao determinados. La fuente de caracteres define la apariencia, tamao, estilo (itlica, negrilla, norma) de la cadena de texto que se va a pintar con esa fuente de caracteres.Una familia de fuentes de caracteres no consiste solamente en un conjunto de fuentes con una apariencia similar, sino tambin de diferentes tamaos y estilos; por ejemplo, la fuente de caracteres Helvetica negrilla de 10 puntos y la fuente Helvetica itlica de 12 puntos, son fuentes de caracteres de la misma familia.La clase Font permite crear objetos de tipo Font y, adems, proporciona constantes simblicas que permiten establecer las caractersticas del objeto Font instanciado. No obstante, antes de instanciar un objeto Font, es necesario saber las fuentes de caracteres de que dispone el sistema y sus nombres. Las fuentes de caracteres tiene un nombre lgico, un nombre de familia y un nombre de fuente. El nombre lgico es el nombre que corresponde a una de las fuentes especificas del sistema y se puede obtener llamando al mtodo getName() de la clase Font. El nombre de familia es el que corresponde al diseo tipogrfico y se sabe invocando al mtodo getFamily() de la clase Font. El nombre de fuente ya determina una fuente de caracteres dentro de una familia concreta, por ejemplo, Helvetica Bold; se sabe llamando al mtodo de la clase Font, getFontName(). Para determinar todas las fuentes disponibles en el sistema hay que llamar al mtodo getAllFonts() de la clase GraphicsEnvironment.La forma ms sencilla de crear un objeto de tipo Font es indicar un nombre de fuente, tamao en puntos y estilo. Una vez que se ha instanciado un objeto Font, se puede derivar de l cualquier nmero de nuevos objetos de tipo Font llamando al mtodo deriveFont() sobre el objeto Font existente y especificando un nuevo tamao de puntos, estilo, transformacin (posicin, escala, rotacin, inclinacin) o mapa de atributos, por ejemplo:Font fuenteBold = new Font( "Helvetica",Font.BOLD,12 );Font fDerivItalica = fuenteBold.deriveFont( Font.ITALIC,12 );Font fDerivPlain = fuenteBold.deriveFont( Font.PLAIN,14 );Una vez que se tiene una fuente, ya se puede utilizar para pintar cualquier texto. El JDK incluye un conjunto de fuentes TrueType, a las que denomina fuentes fsicas, para distinguirlas de las fuentes lgicas, como la fuente Monospaced, que se encuentran mapeadas en el fichero font.properties a las fuentes de la plataforma correspondiente.La incorporacin de las fuentes fsicas permite que las aplicaciones tengan la misma apariencia en cualquiera de las plataformas, al utilizar el mismo conjunto de fuentes. Adems, no es necesario cambiar de fuente para poder utilizar alfabetos diferentes, por ejemplo, en un campo de texto que utilice la fuente Lucida Sans Regular, se pueden presentar caracteres en hebreo, rabe, alemn e ingls. Y, por supuesto, todas las fuentes fsicas soportan el smbolo del Euro, la moneda nica europea.Actualmente, todas las fuentes fsicas del JDK se engloban dentro de la familia de fuentes Lucida. Esta familia contiene 3 grupos: Sans, Bright y Typewriter, con 4 fuentes en cada grupo: Regular, Bold, Oblique y Bold Oblique. No obstante, con el JDK 1.2 se puede acceder a todas las fuentes disponibles en el sistema, o al menos a todas aquellas que se encuentren en el directorio especificado en la variable de entorno JAVA_FONTS.La clase FontMetricsUn objeto de tipo FontMetrics proporciona toda la informacin necesaria sobre una determinada fuente de caracteres, lo que puede resultar imprescindible a la hora de posicionar un texto en la pantalla. La informacin que FontMetrics proporciona cuando se instancia sobre una determinada fuente incluye la lnea de base, la parte ascendente, la parte descendente, el ancho de los caracteres y el espacio que hay que dejar entre un carcter y el siguiente. Incluso es posible obtener informacin sobre el tamao total de una cadena de texto cuando de pinta con una determinada fuente.Se proporciona mucha informacin, por lo que el lector deber recurrir a la documentacin del JDK, ya que no es motivo de tratamiento aqu el pintado de textos en detalle, aunque se ver posteriormente al tratar del API de grficos 2D, en que se manipularn las fuentes de caracteres para conseguir efectos que no proporcionan las clases base del AWT.La figura siguiente muestra grficamente a qu corresponden algunos de los datos que un objeto de tipo FontMetrics puede proporcionar sobre una determinada fuente de caracteres.

Hay que hacer notar al lector, no obstante, que el tamao de la fuente devuelto por el mtodo getSize() de la clase Font, es una medida abstracta; tericamente, corresponde a la suma de la parte ascendente y la parte descendente; pero en la prctica es el diseador de la fuente el que decide exactamente a qu se refiere una fuente de "12 puntos". Por ejemplo, la fuente Times de 12 puntos es ligeramente ms pequea que la fuente Helvtica de 12 puntos, siendo un punto aproximadamente 1/72 de una pulgada.El ejemplo java1517.java muestra cmo se utilizan algunos de los mtodos de las clases anteriores, teniendo en cuenta que el autor ha capturado la ventana ejecutando el ejemplo sobre Window NT 4.0, por lo que la lista de fuentes disponibles se adeca a las que se encontraban instaladas, que puede no coincidir en absoluto con las fuentes de que disponga en lector en su plataforma especfica.import java.awt.*;import java.awt.event.*;

// Clase de control del ejemploclass java1517 extends Frame {

// Contructor de la clasepublic java1517() { this.setTitle( "Tutorial de Java, Grficos" );this.setSize( 400,300 );this.setVisible( true );

// Clase anidada que permite terminar la ejecucin de la animacinthis.addWindowListener(// Definicin de la clase annima para controlar el cierre de// la ventananew WindowAdapter() {public void windowClosing( WindowEvent evt ) {// Se concluye el programaSystem.exit( 0 );}} );}

// Mtodo de control del programapublic static void main( String[] args ) {// Se instancia un objeto de esta clasenew java1517();}

// Se sobrecarga el mtodo paint()public void paint( Graphics g ) {// Trasladamos el origen de coordenadas que se sita en la// esquina superior izquierda, para evitar el problema que se// produce con insets. g.translate( this.getInsets().left,this.getInsets().top );

// Obtenemos la lista completa de fuentes del sistemaString[] fuentes = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();

// Fijamos una fuente cualquiera, la quinta de la lista por ejemplo,// le cambiamos el estilo a Negrita y su tamao a 14 puntos g.setFont( new Font( fuentes[4],Font.PLAIN,14 ) );// Obtenemos la altura de la fuente seleccionadaint alto = g.getFontMetrics().getHeight();// Fijamos la coordena Y utilizando la altura de la fuente como valor int y = alto;

// Presentamos un rtulo general para la presentacin String rotulo = "Algunas de las fuentes disponibles son:";g.drawString( rotulo,5,y );

// Cambiamos a color rojog.setColor( Color.red );

// Presentamos una pequea lista de todas las fuentes del sistema// indicando el nombre que tiene almacenado el sistema para ellas,// le cambiamos el estino a Negrita y Oblicuafor( int i=78; i < 84; i++ ) {g.setFont( new Font( fuentes[i],Font.BOLD | Font.ITALIC,18) );alto = g.getFontMetrics().getHeight();g.drawString( fuentes[i],160-(g.getFontMetrics().stringWidth(fuentes[i]))/2,y+=alto );}

// Cambiamos a color azulg.setColor( Color.blue );// Volvemos a coger la fuente del rtulo y le cambiamos el estilo a// fuente Normal de 15 puntosg.setFont( new Font( fuentes[4],Font.PLAIN,15 ) );alto = g.getFontMetrics().getHeight(); // Presentamos otro rtulo y += alto;g.drawString( "Informacin sobre la fuente de este texto: ",5,y );// Presentamos informacin sobre la fuente actual y += alto;g.drawString( "" + g.getFont(),5,y );

// Presentamos otro rtulo y += 2*alto;g.drawString( "Aqu est parte de este Tutorial: ",5,y );

// Creamos un array de letras para presentarlo char aTexto[] = {'T','u','t','o','r','i','a','l',' ','d','e',' ','J','a','v','a'};y += alto;// Presentamos en pantalla el array de letras, saltndonos el// primero y no presentado el ltimog.drawChars( aTexto,1,13,5,y ); }}En el programa, se genera un array de cadenas conteniendo los nombres de cada una de las fuentes de caracteres disponibles en el sistema, presentando a continuacin algunas de ellas indicando su propio nombre. El paso de lnea se va incrementando en cada una de las lneas de texto que se presentan en pantalla. De nuevo se recomienda al lector, que a la hora de trabajar con fuentes de caracteres, tenga a mano la documentacin del JDK, ya que hay infinidad de mtodos para obtener y cambiar datos de las fuentes, y ninguno de ellos es difcil de entender.La imagen siguiente muestra la ventana resultado de la ejecucin del ejemplo anterior.

Recuerde el lector que la plataforma de ejecucin era Windows NT 4.0.

La clase Graphics, Mtodos para Imgenes

Anterior | Siguiente

Mtod