Dibujar Formas

La clase Graphics define métodos para dibujar los siguientes tipos de formas:

Excepto para los polígonos y las líneas todas las formas son especificas utilizando su rectángulo exterior. Una vez que hayas comprendido el dibujo de rectángulos, las otras formas son relativamente sencillas. Por esta razón, esta página se concentra en el dibujo de rectángulos.

Ejemplo 1: Dibujar un Rectángulo Sencillo

El applet de la página anterior usa los métodos draw3DRect() y fillRect() para dibujar su interface. Aquí está el applet de nuevo:


Nota: Como algunos viejos navegadores no soportan 1,1, el applet anterior es una versión 1.0, (aquí está código 1.0; y aquí está el codigo 1.1). Para ejecutar la versión 1.1 del applet, puedes ir a example-1dot1/CoordinatesDemo.html. Para más información sobre la ejecución de applets puedes ver Sobre Nuestros Ejemplos.

Aquí está el código de dibujo:

//In FramedArea (a Panel subclass):
public void paint(Graphics g) {
    Dimension d = size();
    Color bg = getBackground();
 
    //Draw a fancy frame around the applet.
    g.setColor(bg);
    g.draw3DRect(0, 0, d.width - 1, d.height - 1, true);
    g.draw3DRect(3, 3, d.width - 7, d.height - 7, false);
}

//In CoordinateArea (a Canvas subclass):
public void paint(Graphics g) {
    //If user has clicked, paint a tiny rectangle where click occurred
    if (point != null) {
        g.fillRect(point.x - 1, point.y - 1, 2, 2);
    }
}
El applet crea (y contiene) un objeto FramedArea, que crea (y contiene) un objeto CoordinateArea. La primera llamada a draw3DRect() crea un rectángulo tan grande como el área de dibujo del FramedArea. El argumento true especifica que el rectángulo debe aparecer elevado. La segunda llamada a draw3DRect() crea un segundo rectángulo un poquito menor, con false especifica que el rectángulo deberá aparcer embebido. Las dos llamadas juntas producen el efecto de un marco elvado que contiene el CoordinateArea. (FramedArea implementa el método insets() para que el área de dibujo de la CoordinateArea esté unos pixels dentro del FramedArea.)

El CoordinateArea utiliza fillRect() para dibujar un rectángulo de 2x2 pixles en el punto en el que el usuario pulsa el botón del ratón.

Ejemplo 2: Usar un Rectángulo para Indicar un Área Seleccionada

Aquí tienes un applet que podrías utilizar para implementar la selección básica en un programa de dibujo. Cuando el usuario mantiene pulsado el botón del ratón, el applet muestra continuamente un rectángulo. El rectángulo empieza en la posición del cursor cuando el usuario pulsó el botón del ratón por primera vez y termina en la posición actual del cursor.


Nota: Como algunos viejos navegadores no soportan 1,1, el applet anterior es una versión 1.0, (aquí está código 1.0; y aquí está el codigo 1.1). Para ejecutar la versión 1.1 del applet, puedes ir a example-1dot1/RectangleDemo.html. Para más información sobre la ejecución de applets puedes ver Sobre Nuestros Ejemplos.

Aquí puedes ver el nuevo código más significativo:

class SelectionArea extends Canvas {
    . . .

    public boolean mouseDown(Event event, int x, int y) {
        currentRect = new Rectangle(x, y, 0, 0);
        repaint();
        return false;
    }
    
    public boolean mouseDrag(Event event, int x, int y) {
        currentRect.resize(x - currentRect.x, y - currentRect.y);
        repaint();
        return false;
    }
    
    public boolean mouseUp(Event event, int x, int y) {
        currentRect.resize(x - currentRect.x, y - currentRect.y);
        repaint();
        return false;
    }
    
    public void paint(Graphics g) {
        Dimension d = size();
    
        //If currentRect exists, paint a rectangle on top.
        if (currentRect != null) {
            Rectangle box = getDrawableRect(currentRect, d);
            controller.rectChanged(box);
        
            //Draw the box outline.
            g.drawRect(box.x, box.y, box.width - 1, box.height - 1);
        }
    }
    
    Rectangle getDrawableRect(Rectangle originalRect, Dimension drawingArea) {
        . . .
        //Make sure rectangle width and height are positive.
        . . .
        //The rectangle shouldn't extend past the drawing area.
        . . .
    }
}
Como puedes ver, el SelectionArea sigue la pista del rectángulo seleccionado actualmente, utilizando un objeto Rectangle llamado currentRect. Debido a la implementación, el currentRect mantiene el mismo origen (currentRect.x, currentRect.y) mientras el usuario arrrastre el ratón. Esto significa que la altura y anchura del rectángulo podrían ser negativas.

Sin embargo, los métodos drawXxx() y fillXxx() no dibujarán nada si su altura o anchura son negativos. Por esta razón, cuando SelectionArea dibuja un rectángulo, debe especificar el vértice superior izquierdo del rectángulo para que la altura y la anchura sean positivas. La clase SelectionArea define el método getDrawableRect() para realizar los cálculos necesarios para encontrar el vértice superior izquierdo. El getDrawableRect() método también se asegura de que el rectángulo no sobrepase los límites de su área de dibujo. Aquí tienes de nuevo un enlace al código fuente. Encontrarád la definición de getDrawableRect() al final del fichero.

Nota: Es perfectamente legal especificar valores negativos para x, y, height o width o hacer que el resultado sea mayor que el área de dibujo. Los valores fuera del área de dibujo no importan demasiado porque son recortardos al área de dibujo. Lo único es que no verás una parte de la forma. La altura o anchura negativas dan como resultado que no se dibujará nada en absoluto.

Ejemplo 3: Un Ejemplarizador de formas

El siguiente applet demuestra todas las formas que se pueden dibujar y rellenar.


Nota: Como algunos viejos navegadores no soportan 1,1, el applet anterior es una versión 1.0, (aquí está código 1.0; y aquí está el codigo 1.1). Para ejecutar la versión 1.1 del applet, puedes ir a example-1dot1/ShapesDemo.html. Para más información sobre la ejecución de applets puedes ver Sobre Nuestros Ejemplos.

A menos que la fuente por defecto de su visualizador de applets sea muy pequeña, el texto mostrado en el applet anterior podría parecer demasiado grande en ocasiones. La palabras podrían dibujarse unas sobre otras. Y como este applet no utiliza el método insets() para proteger sus límites el texto podría dibujarse sobre el marco alrededor del applet. La siguiente página amplía este ejemplo, enseñándolo como hacer que el texto quepa en un espacio dado.

Aquí sólo está el código que dibuja las formas geométricas. Las variables rectHeight y rectWidth especifican el tamaño en pixels del área en la que debe dibujarse cada forma. Las variables x e y se cambian para cada forma, para que no se dibujen unas encimas de las otras.

Color bg = getBackground();
Color fg = getForeground();
. . .

// drawLine() 
g.drawLine(x, y+rectHeight-1, x + rectWidth, y); // x1, y1, x2, y2
. . .

// drawRect() 
g.drawRect(x, y, rectWidth, rectHeight); // x, y, width, height
. . .

// draw3DRect() 
g.setColor(bg);
g.draw3DRect(x, y, rectWidth, rectHeight, true);
g.setColor(fg);
. . .

// drawRoundRect() 
g.drawRoundRect(x, y, rectWidth, rectHeight, 10, 10); // x, y, w, h, arcw, arch
. . .

// drawOval() 
g.drawOval(x, y, rectWidth, rectHeight); // x, y, w, h
. . .

// drawArc() 
g.drawArc(x, y, rectWidth, rectHeight, 90, 135); // x, y, w, h
. . .

// drawPolygon() 
Polygon polygon = new Polygon();
polygon.addPoint(x, y);
polygon.addPoint(x+rectWidth, y+rectHeight);
polygon.addPoint(x, y+rectHeight);
polygon.addPoint(x+rectWidth, y);
//polygon.addPoint(x, y); //don't complete; fill will, draw won't
g.drawPolygon(polygon); 
. . .

// fillRect() 
g.fillRect(x, y, rectWidth, rectHeight); // x, y, width, height
. . .

// fill3DRect() 
g.setColor(bg);
g.fill3DRect(x, y, rectWidth, rectHeight, true);
g.setColor(fg);
. . .

// fillRoundRect() 
g.fillRoundRect(x, y, rectWidth, rectHeight, 10, 10); // x, y, w, h, arcw, arch
. . .

// fillOval() 
g.fillOval(x, y, rectWidth, rectHeight); // x, y, w, h
. . .

// fillArc() 
g.fillArc(x, y, rectWidth, rectHeight, 90, 135); // x, y, w, h
. . .

// fillPolygon() 
Polygon filledPolygon = new Polygon();
filledPolygon.addPoint(x, y);
filledPolygon.addPoint(x+rectWidth, y+rectHeight);
filledPolygon.addPoint(x, y+rectHeight);
filledPolygon.addPoint(x+rectWidth, y);
//filledPolygon.addPoint(x, y);
g.fillPolygon(filledPolygon); 

Ozito