| Working with Graphics

## Drawing Shapes

> The Graphics class defines methods for drawing the following kinds of shapes:
> - Lines (`drawLine()`, which draws a line in the Graphics object's current color, which is initialized to the Component's foreground color)
> - Rectangles (`drawRect()`, `fillRect()`, and `clearRect()` -- where `fillRect()` fills a rectangle with the Graphics object's current color, and `clearRect()` fills a rectangle with the Component's background color)
> - Raised or lowered rectangles (`draw3DRect()` and `fill3DRect()`)
> - Round-edged rectangles (`drawRoundRect()` and `fillRoundRect()`)
> - Ovals (`drawOval()` and `fillOval()`)
> - Arcs (`drawArc()` and `fillArc()`)
> - Polygons (`drawPolygon()` and `fillPolygon()`)
> Except for polygons and lines, all shapes are specified using their bounding rectangle. Once you understand rectangles, drawing other shapes is relatively easy. For this reason, this page concentrates on rectangle drawing.

> #### Example 1: Simple Rectangle Drawing

> > The applet on the previous page used the `draw3DRect()` and `fillRect()` methods to draw its interface. Here's the applet again:

> > Here's its code. Below is just the drawing code:

> > >     //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);
> > >         }
> > >     }

> > The applet creates (and contains) a FramedArea object, which in turn creates (and contains) a CoordinateArea object. The first call to `draw3DRect()` creates a rectangle as big as the FramedArea's drawing area. The `true` argument specifies that the rectangle should appear to be raised. The second call to `draw3DRect()` creates a second rectangle just a bit smaller, with `false` specifying that the rectangle should appear to be sunken. Together, the two calls produce the effect of a raised frame that contains the CoordinateArea. (FramedArea implements the `insets()` method so that the CoordinateArea's drawing area is a few pixels inside of the FramedArea.)

> > The CoordinateArea uses `fillRect()` to draw a two-by-two-pixel rectangle at the point that the user clicks.

> #### Example 2: Using a Rectangle to Indicate a Selected Area

> > Here's an applet that you could use as a basis for implementing selection in a drawing program. When the user drags the mouse, the applet continuously displays a rectangle. The rectangle starts at the cursor position where the user first pressed the mouse button and ends at the current cursor position.

> > Here's the applet's code. Below is the significant new code:

> > >     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.
> > >             . . .
> > >         }
> > >     }

> > As you can see, the SelectionArea keeps track of the currently selected rectangle, using a Rectangle object called `currentRect`. As implemented, the `currentRect` keeps the same origin (`currentRect.x`, `currentRect.y`) for as long as the user drags the mouse. This means that the height and width of the rectangle can be negative.

> > However, the `drawXxx()` and `fillXxx()` methods don't draw anything if either the height or width is negative. For this reason, when the SelectionArea draws the rectangle, it must specify the upper left vertex of the rectangle so that the width and height are positive. The SelectionArea class defines a `getDrawableRect()` method to perform the necessary calculations to find the upper left vertex. The `getDrawableRect()` method also makes sure that the rectangle doesn't extend beyond the boundaries of its drawing area. Here, again is a link to the source code. You'll find the definition of `getDrawableRect()` at the bottom of the file.

> > Note: It's perfectly legal to specify x, y, height, or width values that are negative or cause a result larger than the drawing area. Values outside the drawing area don't matter too much because they're clipped to the drawing area. You just won't see part of the shape. Negative height or width results in the shape not being drawn at all.

> #### Example 3: A Shape Sampler

> > The following applet demonstrates all the shapes you can draw and fill.

> > Unless your applet viewer's default font is very small, the text displayed in the above applet might look ugly in places. Words might be drawn on top of each other. And because this applet doesn't use the `insets()` method to protect its boundaries, text might be drawn on top of the frame around the applet. The next page improves on this example, teaching you how to make sure text fits within a given space.

> > Here's the code for the shape-drawing applet. Here's just the code that draws the geometric shapes. The `rectHeight` and `rectWidth` variables specify the size in pixels of the area each shape must be drawn in. The `x` and `y` variables are changed for every shape, so that the shapes aren't drawn on top of each other.

> > >     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);

| Working with Graphics