Chapter 16

Drawing Graphics


CONTENTS

Almost all applets need to create some sort of display, whether that display is as simple as a line of text or as sophisticated as an animation sequence. Because Windows is a graphical system, everything you see on the screen during a Windows session is displayed graphically. This is true even of text. Because of its graphical nature, a system like Java's must include the capability to handle device-independent graphics. In this chapter, you see not only how you can display various graphical shapes, but also how to query the system about the characteristics of the display.

The Applet's Canvas

Every applet has an area of the screen, called the canvas, in which it can create its display. The size of an applet's canvas depends on the size of the applet, which is in turn controlled by the parameters included in an HTML document's <applet> tag. Generally, the larger the applet appears in the HTML document, the larger the applet's visible canvas. Anything that you try to draw outside of the visible canvas doesn't appear on the screen.

You draw graphical images on the canvas by using coordinates that identify pixel locations. Chances are good that you've had some sort of computer-graphics experience before Java, so you know that the coordinates that define pixel locations on a computer screen can be organized in various ways. Windows, for example, supports a number of different mapping modes that determines how coordinates are calculated in a window.

Thankfully, Java does away with the complications of displaying graphics in a window by adopting a single coordinate system. This coordinate system has its origin (point 0,0) in the upper-left corner, with the X axis increasing to the right, and the Y axis increasing downward, as shown in Figure 16.1.

Figure 16.1 : An applet's canvas uses the typical computer-display coordinate system.

Example: Using the Coordinate System

When you want to draw something on an applet's canvas, you use the coordinate system shown in Figure 16.1. This coordinate system situates the system's origin in the applet's upper-left corner, just as it's shown in Figure 16.1. For example, Figure 16.2 shows an applet displaying a single line in its canvas. This line was drawn starting at coordinates 5,10, as shown in Figure 16.3.

Figure 16.2 : This applet displays a single line.

Figure 16.3 : The line in Figure 16.2 is drawn at the coordinates 5,10.

Drawing Shapes

Java's Graphics class includes methods for drawing many different types of shapes, everything from straight lines to polygons. You were introduced to the Graphics class in Part II of this book when you displayed text in an applet's paint() method. As you may recall, a reference to a Graphics object is passed to the paint() method as its single argument. Because the Graphics class is part of the awt package, you have to include one of the following lines at the top of your applet's code to use the class:


import java.awt.Graphics

import java.awt.*

The first line in the preceding imports only the Graphics class, whereas the second line imports all the classes included in the awt package. Table 16.1 lists the most commonly used drawing methods in the Graphics class.

Table 16.1  Drawing Methods of the Graphics Class.

MethodDescription
clearRect()Erases a rectangular area of the canvas.
copyArea()Copies a rectangular area of the canvas to another area.
drawArc()Draws a hollow arc.
drawLine()Draws a straight line.
drawOval()Draws a hollow oval.
drawPolygon()Draws a hollow polygon.
drawRect()Draws a hollow rectangle.
drawRoundRect()Draws a hollow rectangle with rounded corners.
drawString()Displays a text string.
fillArc()Draws a filled arc.
fillOval()Draws a filled oval.
fillPolygon()Draws a filled polygon.
fillRect()Draws a filled rectangle.
fillRoundRect()Draws a filled rectangle with rounded corners.
getColor()Retrieves the current drawing color.
getFont()Retrieves the currently used font.
getFontMetrics()Retrieves information about the current font.
setColor()Sets the drawing color.
setFont()Sets the font.

To draw a shape in an applet's display area, you only need to call the appropriate method and supply the arguments required by the method. These arguments are based on the coordinates at which you want to draw the shape. For example, the following code example draws a straight line from coordinate 5,10 to 20,30:


g.drawLine(5, 10, 20, 30);

The g in the preceding code line is the Graphics object passed to the paint() method. As you can see, the drawLine() method takes four arguments, which are X,Y coordinate pairs that specify the starting and ending points of the line.

TIP
There may be times when you need to retrieve information about the system's currently set graphical attributes. Java's Graphics class supplies methods like getColor(), getFont(), and getFontMetrics() to enable you to obtain this information.

Example: Drawing a Rectangle

Most of the shape-drawing methods are as easy to use as the drawLine() method is. Suppose that you want to write an applet that draws a filled rounded rectangle inside a hollow rectangle. You'd then add calls to the Graphics class's fillRoundRect() and drawRect() to the applet's paint() method. Listing 16.1 is just such an applet, whereas Listing 16.2 is the HTML document that displays the applet. Figure 16.4 shows the applet running under Appletviewer.

Figure 16.4 : This is RectApplet running under Appletviewer.


Listing 16.1  RECTAPPLET.JAVA: Drawing Rectangles.

import java.awt.*;

import java.applet.*;



public class RectApplet extends Applet

{

    public void paint(Graphics g)

    {

        g.drawRect(35, 15, 125, 200);

        g.fillRoundRect(50, 30, 95, 170, 15, 15);

    }

}



Listing 16.2  RECTAPPLET.htmL: HTML Document for RectApplet.

<title>Applet Test Page</title>

<h1>Applet Test Page</h1>

<applet

    code="RectApplet.class"

    width=200

    height=250

    name="RectApplet">

</applet>


In RectApplet's paint() method, you can see the method calls that produce the graphical display. The first line creates the outside rectangle. That method call looks like this:


g.drawRect(35, 15, 125, 200);

The drawRect() method's four arguments are the X,Y coordinates of the rectangle's upper-left corner and the width and height of the rectangle. The rounded filled rectangle is almost as easy to draw:


g.fillRoundRect(50, 30, 95, 170, 15, 15);

The first four arguments of the fillRoundRect() method are the same as those for the drawRect() method. The fifth and sixth arguments are the size of the rectangle that represents the rounded corners. Think of this rectangle as being placed on each corner of the main rectangle and a curved line drawn between its corners, as shown in Figure 16.5.

Figure 16.5 : The coordinates for the rounded corners are given as the width and height of the rectangle that encloses the rounded corner.

Example: Drawing Other Shapes

Some shapes you can draw with the Graphics class are more complex than others. For example, the drawArc() method requires six arguments in order to draw a simple curved line. To see how drawing other shapes works, you'll now create the ShapeApplet applet, which enables you to switch from one shape to another in the applet's display. Listing 16.3 is ShapeApplet's source code. Figures 16.6 and 16.7 show what the applet looks like running under the Appletviewer application.

Figure 16.6 : This is what ShapeApplet looks like when it first runs.

Figure 16.7 : This is ShapeApplet displaying an oval.


Listing 16.3  ShapeApplet.java: An Applet That Draws Various Shapes.

import java.awt.*;

import java.applet.*;



public class ShapeApplet extends Applet

{

    int shape;

    Button button;



    public void init()

    {

        shape = 0;

        button = new Button("Next Shape");

        add(button);

    }



    public void paint(Graphics g)

    {

        int x[] = {35, 150, 60, 140, 60, 150, 35};

        int y[] = {50, 80, 110, 140, 170, 200, 230};

        int numPts = 7;



        switch(shape)

        {

            case 0:

                g.drawLine(35, 50, 160, 230);

                break;

            case 1:

                g.drawRect(35, 50, 125, 180);

                break;

            case 2:

                g.drawRoundRect(35, 50, 125, 180, 15, 15);

                break;

            case 3:

                g.drawOval(35, 50, 125, 180);

                break;

            case 4:

                g.drawArc(35, 50, 125, 180, 90, 180);

                break;

            case 5:

                g.drawPolygon(x, y, numPts);

                break;

            case 6:

                g.fillPolygon(x, y, numPts);

                break;

        }

    }



    public boolean action(Event event, Object arg)

    {

        ++shape;

        if (shape == 7)

            shape = 0;

        repaint();

        return true;

    }

}


Tell Java that the applet uses the classes in the awt package.
Tell Java that the applet uses the classes in the applet package.
Derive the ShapeApplet class from Java's Applet class.
Declare the class's shape data field.
Declare the class's button data field.
Override the init() method.
Initialize the shape counter.
Create the applet's Button object.
Add the Button object to the applet.
Override the paint() method.
Initialize the X and Y coordinates for the polygons.
Initialize the polygon point count.
Display a shape based on the value of the shape counter.
Override the action() method.
Increment the shape counter.
Reset the shape counter if it has reached its maximum value.
Force the applet to repaint its canvas with the next shape.
Tell Java that the method executed okay.

To run ShapeApplet, use the HTML document shown in Listing 16.2, except change all occurrences of RectApplet to ShapeApplet. When you run the applet with Appletviewer, you see the window shown in Figure 16.6. To change the shape displayed in the applet's canvas, click the Next Shape button.

Understanding the ShapeApplet Applet

You don't need to concern yourself at this point with the button control that ShapeApplet uses to switch shapes, except to know that just like the TextField controls you've been using, clicking the button causes Java to call the applet's action() method. The action() method increments the shape counter, shape, and tells the applet to redraw itself. In the paint() method, the value of shape is used in a switch statement to determine which shape gets drawn. You learned about switch statements back in Chapter 9 "The if and switch Statements."

Drawing Ovals

The real meat of this program are the calls to the Graphics object's various shape-drawing methods. You already know about the first three: drawLine(), drawRect(), and drawRoundRect(). The call to drawOval(), however, is new and looks like this:


g.drawOval(35, 50, 125, 180);

As you can see, this method, which draws ovals and circles, takes four arguments. These arguments are the X,Y coordinates, width, and height of a rectangle that can enclose the oval. Figure 16.8 shows how the resultant oval relates to its enclosing rectangle.

Figure 16.8 : An oval's coordinates are actually the coordinates of an enclosing rectangle.

Drawing Arcs

Next in paint() is the drawArc() method, which is the most complicated (at least, from an understanding point of view) of the shape-drawing methods. The call to drawArc() looks like this:


g.drawArc(35, 50, 125, 180, 90, 180);

The first four arguments are the same as the arguments for drawOval(): the X,Y coordinates, width, and height of the enclosing rectangle. The last two arguments are the angle at which to start drawing the arc and the number of degrees around the arc to draw.

To understand all this angle nonsense, take a look at figure 16.9, which shows how Java relates the arc's starting angle to the degrees of an oval. In the preceding example call to drawArc(), the fifth argument is 90, which means Java starts drawing the arc, within the arc's enclosing rectangle, at the 90-degree point. The sixth argument of 180 tells Java to draw around the arc 180 degrees (or halfway around the full 360 degrees). It doesn't mean that the ending point should be at the 180-degree point. Figure 16.10 shows the resultant arc.

Figure 16.9 : The degrees of an oval start on the right side and travel counter-clockwise around the arc.

Figure 16.10 : The arc shown here starts at the 90-degree point and sweeps 180 degrees around the arc.

Example: Drawing Arcs in an Applet

Because understanding the angles involved in drawing arcs can be a little confusing, in this example you'll create an applet called ArcApplet that enables you to enter different values for drawArc()'s fifth and sixth arguments and immediately see the results. Listing 16.4 is the source code for the applet. Use Listing 16.2 to create ArcApplet's HTML document, by changing each occurrence of RectApplet to ArcApplet.


Listing 16.4  ARCAPPLET.JAVA: An Arc-Drawing Applet.

import java.awt.*;

import java.applet.*;



public class ArcApplet extends Applet

{

    TextField textField1, textField2;



    public void init()

    {

        textField1 = new TextField(10);

        textField2 = new TextField(10);



        add(textField1);

        add(textField2);



        textField1.setText("0");

        textField2.setText("360");

    }



    public void paint(Graphics g)

    {

        String s = textField1.getText();

        int start = Integer.parseInt(s);



        s = textField2.getText();

        int sweep = Integer.parseInt(s);



        g.drawArc(35, 50, 125, 180, start, sweep);

    }



    public boolean action(Event event, Object arg)

    {

        repaint();

        return true;

    }

}


Tell Java that the applet uses the classes in the awt package.
Tell Java that the applet uses the classes in the applet package.
Derive the ArcApplet class from Java's Applet class.
Declare the class's TextField objects.
Override the init() method.
Create the two TextField objects.
Add the TextField objects to the applet.
Set the text for the TextField objects.
Override the paint() method.
Get the starting angle and convert it to an integer.
Get the sweep angle and convert it to an integer.
Display the selected arc.
Override the action() method.
Force the applet to repaint its canvas with the next shape.
Tell Java that the method executed okay.

When you run ArcApplet using Appletviewer, you see the window shown in Figure 16.11. (Looks kind of like a guy with shifty eyes and a big nose, doesn't it?) Because the starting angle (in the first text box) is 0 and the drawing degrees (the second box) is 360, the arc is actually a full oval. By changing the values in the two boxes and pressing Enter, you can cause the applet to display different arcs. For example, Figure 16.12 shows an arc that has a starting angle of 120 degrees and drawing degrees of 245.

Figure 16.11 : This is ArcApplet at startup.

Figure 16.12 : You can use ArcApplet to experiment with different arc angle settings.

NOTE
Most of the shape-drawing methods come in two versions, one that draws a hollow shape and one that draws a filled shape. The method that draws the filled shape has the same name as the one that draws the hollow shape, except you change the word draw in the name to fill. For example, because drawArc() draws a hollow arc, the method fillArc() draws a filled arc.

Drawing Polygons

Polygons are simply many-sided shapes. For example, a triangle is a polygon (it is, in fact, the simplest polygon). Squares, rectangles, and hexagons are all polygons, as well. Because a polygon comprises many different lines, before you can draw a polygon in Java, you need to create arrays that contain the X,Y coordinates for each line in the polygon. In Listing 16.3, ShapeApplet defines those arrays like this:


int x[] = {35, 150, 60, 140, 60, 150, 35};

int y[] = {50, 80, 110, 140, 170, 200, 230};

int numPts = 7;

The first array, called x[] in the preceding, is the X coordinates for each X,Y pair, and the second array, called y[], is the Y coordinates for each X,Y pair. By looking at the values defined in the arrays, you can see that the first line gets drawn from 35,50 to 150,80. Because all the lines in a polygon are connected, Java can continue drawing lines by using the previous ending point (in this case, 150,80) and the next coordinate pair, which is 60,110. Java will continue to work through the arrays until it uses all the given coordinates. The actual method call that draws the polygon looks like this:


g.drawPolygon(x, y, numPts);

The drawPolygon() method's three arguments are the array holding the X coordinates, the array holding the Y coordinates, and the number of points defined in the arrays. You can use a literal value for the third argument, but it's often handy to define a variable as shown in the example (numPts). Then, if you change the arrays, you can change the variable at the same time and not have to worry about correcting any method calls that use the arrays along with point count.

Figure 16.13 shows the polygon drawn by the values given in the x[] and y[] arrays in the preceding. Looks more like a squiggly line than a polygon. That's because when you draw a hollow polygon, Java doesn't connect the starting and ending point. If you draw a filled polygon, though, you'll see that the connecting side is really there, as shown in Figure 16.14.

Figure 16.13 : A hollow polygon is always missing one side.

Figure 16.14 : A filled polygon actually looks like a polygon instead of a squiggly line.

NOTE
If you need more control over your polygons, Java includes a Polygon class from which you can create polygon objects from the coordinate arrays. The Polygon class includes handy methods that enable you to add points to a polygon, determine whether a point is inside the polygon, and retrieve the polygon's bounding rectangle. You create a Polygon object with a line like Polygon polygon = new Polygon(x, y, numPts). The arguments for the class's constructor are the same as those for the drawPolygon() method. The Polygon class's public methods are addPoint(x, y), getBoundingBox() (which returns a Rectangle object), and inside() (which returns a boolean value).

Summary

Java's Graphics class enables you to draw many types of shapes, including lines, rectangles, ovals, and arcs. You can use these shape-drawing methods to enhance the appearance of your applets, drawing frames around objects, and even putting together simple illustrations. In addition, you can set the drawing color used by the Graphics class, as well as query the system for its current graphics settings. In the next chapter, you add to your graphics knowledge by learning how to create, manipulate, and display graphical text.

Review Questions

  1. What do you call the area of an applet in which you can draw?
  2. How is Java's graphical coordinate system organized?
  3. What is the difference in the shapes drawn by the drawRect() and fillRect() methods?
  4. What are the four arguments for the drawRect() method?
  5. How do the arguments for the drawRoundRect() method differ from the arguments for drawRect()?
  6. Why does the drawPolygon() method require that you set up arrays of coordinates?
  7. What are the six arguments required by the drawArc() method?
  8. Why would you want to use the polygon class?

Review Exercises

  1. Write the code needed to draw a 100´200 rectangle at the coordinates 50,75.
  2. Write an applet that displays a square inside a circle.
  3. Write an applet that enables the user to choose the width, height, and location of a rectangle. The applet should display the rectangle at the given coordinates.
  4. Modify the ArcApplet applet so that the user can select not only the arc's drawing points, but also the size of the arc's bounding rectangle.
  5. Write an applet called FaceApplet that displays a face made from ovals and arcs. The final applet should look like Figure 16.15. (You can find the solution to this problem in the CHAP16 folder of this book's CD-ROM.)
    Figure 16.15 : This is what FaceApplet should look like when running under Appletviewer.