Tuesday 6 March 2012

Graphics, Fonts, and Color

  • Graphics, Fonts, and Color
    • The Graphics Class
      • The Graphics Coordinate System
    • Drawing and Filling
      • Lines
      • Rectangles
      • Polygons
      • Ovals
      • Arc
      • A Simple Graphics Example
      • Copying and Clearing
    • Text and Fonts
    • Color
      • Using Color Objects
      • Testing and Setting the Current Colors
      • A Single Color Example
    • Summary
    • Q&A


Graphics, Fonts, and Color

by Laura Lemay
Now you have a basic understanding of how applets work. For the remainder of this week you'll cover the sorts of things you can do with applets with the built-in Java class libraries, and how you can combine them to produce interesting effects. You'll start today with how to draw to the screen—that is, how to produce lines and shapes with the built-in graphics primitive, how to print text using fonts, and how to use and modify color in your applets. Today you'll learn, specifically:
  • How the graphics system works in Java: the Graphics class, the coordinate system used to draw to the screen, and how applets paint and repaint
  • Using the Java graphics primitives, including drawing and filling lines, rectangles, ovals, and arcs
  • Creating and using fonts, including how to draw characters and strings and how to find out the metrics of a given font for better layout
  • All about color in Java, including the Color class and how to set the foreground (drawing) and background color for your applet

Note: Today's lesson discusses many of the basic operations available to you with the Java class library regarding graphics, fonts, and color. However, today's lesson, as well as all of this book, is also intended to be more of an introduction and an overview than an exhaustive description of all the features available to you. Be sure to check out the Java API documentation for more information on the classes described today.

The Graphics Class

With Java's graphics capabilities, you can draw lines, shapes, characters, and images to the screen inside your applet. Most of the graphics operations in Java are methods defined in the Graphics class. You don't have to create an instance of Graphics in order to draw something in your applet; in your applet's paint() method (which you learned about yesterday), you are given a Graphics object. By drawing on that object, you draw onto your applet and the results appear on screen.
The Graphics class is part of the java.awt package, so if your applet does any painting (as it usually will), make sure you import that class at the beginning of your Java file:
import java.awt.Graphics;

public class MyClass extends java.applet.Applet {

...

}

The Graphics Coordinate System

To draw an object on the screen, you call one of the drawing methods available in the Graphics class. All the drawing methods have arguments representing endpoints, corners, or starting locations of the object as values in the applet's coordinate system—for example, a line starts at the point 10,10 and ends at the point 20,20.
Java's coordinate system has the origin (0,0) in the top left corner. Positive x values are to the right, and positive y values are down. All pixel values are integers; there are no partial or fractional pixels. Figure 9.1 shows how you might draw a simple square by using this coordinate system.

Figure 9.1. The Java graphics coordinate system.

Java's coordinate system is different from many painting and layout programs that have their x and y in the bottom left. If you're not used to working with this upside-down graphics system, it may take some practice to get familiar with it.

Drawing and Filling

The Graphics class provides a set of simple built-in graphics primitives for drawing, including lines, rectangles, polygons, ovals, and arcs.

Note: Bitmap images, such as GIF files, can also be drawn by using the Graphics class. You'll learn about this tomorrow.

Lines

To draw straight lines, use the drawLine() method. drawLine() takes four arguments: the x and y coordinates of the starting point and the x and y coordinates of the ending point.
public void paint(Graphics g) {

    g.drawLine(25,25,75,75);

}
Figure 9.2 shows the result of this snippet of code.

Figure 9.2. Drawing lines.

Rectangles

The Java graphics primitives provide not just one, but three kinds of rectangles:
  • Plain rectangles
  • Rounded rectangles, which are rectangles with rounded corners
  • Three-dimensional rectangles, which are drawn with a shaded border
For each of these rectangles, you have two methods to choose from: one that draws the rectangle in outline form, and one that draws the rectangle filled with color.
To draw a plain rectangle, use either the drawRect() or fillRect() methods. Both take four arguments: the x and y coordinates of the top left corner of the rectangle, and the width and height of the rectangle to draw. For example, the following paint() method draws two squares: the left one is an outline and the right one is filled (Figure 9.3 shows the result):

Figure 9.3. Rectangles.

public void paint(Graphics g) {

    g.drawRect(20,20,60,60);

    g.fillRect(120,20,60,60);

}
Rounded rectangles are, as you might expect, rectangles with rounded edges. The drawRoundRect() and fillRoundRect() methods to draw rounded rectangles are similar to regular rectangles except that rounded rectangles have two extra arguments for the width and height of the angle of the corners. Those two arguments determine how far along the edges of the rectangle the arc for the corner will start; the first for the angle along the horizontal plane, the second for the vertical. Larger values for the angle width and height make the overall rectangle more rounded; values equal to the width and height of the rectangle itself produce a circle. Figure 9.4 shows some examples of rounded corners.

Figure 9.4. Rounded corners.

Here's a paint() method that draws two rounded rectangles: one as an outline with a rounded corner 10 pixels square; the other, filled, with a rounded corner 20 pixels square (Figure 9.5 shows the resulting squares):

Figure 9.5. Rounded rectangles.

public void paint(Graphics g) {

    g.drawRoundRect(20,20,60,60,10,10);

    g.fillRoundRect(120,20,60,60,20,20);

}
Finally, there are three-dimensional rectangles. These rectangles aren't really 3D; instead, they have a shadow effect that makes them appear either raised or indented from the surface of the applet. Three-dimensional rectangles have four arguments for the x and y of the start position and the width and height of the rectangle. The fifth argument is a boolean indicating whether the 3D effect is to raise the rectangle (true) or indent it (false). As with the other rectangles, there are also different methods for drawing and filling: draw3DRect() and fill3DRect(). Here's code to produce two of them—the left one indented, the right one raised (Figure 9.6 shows the result):

Figure 9.6. Three-dimensional
rectangles.

public void paint(Graphics g) {

    g.draw3DRect(20,20,60,60,true);

    g.draw3DRect(120,20,60,60,false);

}

Note: In the current version of the Java developer's kit, it is very difficult to see the 3D effect on 3D rectangles, due to a very small line width. (In fact, I enhanced Figure 9.6 to better show the effect.) If you are having troubles with 3D rectangles, this may be why. Drawing 3D rectangles in any color other than black makes them easier to see.

Polygons

Polygons are shapes with an unlimited number of sides. To draw a polygon, you need a set of x and y coordinates, and the drawing method then starts at one, draws a line to the second, then a line to the third, and so on.
As with rectangles, you can draw an outline or a filled polygon (the drawPolygon() and fillPolygon() methods, respectively). You also have a choice of how you want to indicate the list of coordinates—either as arrays of x and y coordinates or as an instance of the Polygon class.
Using the first method, the drawPolygon() and fillPolygon() methods take three arguments:
  • An array of integers representing x coordinates
  • An array of integers representing y coordinates
  • An integer for the total number of points
The x and y arrays should, of course, have the same number of elements.
Here's an example of drawing a polygon's outline by using this method (Figure 9.7 shows the result):

Figure 9.7. A polygon.

public void paint(Graphics g) {

    int exes[] = { 39,94,97,142,53,58,26 };

    int whys[] = { 33,74,36,70,108,80,106 };

    int pts = exes.length;

    g.drawPolygon(exes,whys,pts);

}
Note that Java does not automatically close the polygon; if you want to complete the shape, you have to include the starting point of the polygon at the end of the array. Drawing a filled polygon, however, joins the starting and ending points.
The second way of calling drawPolygon() and fillPolygon() is to use a Polygon object. The Polygon class is useful if you intend to add points to the polygon or if you're building the polygon on the fly. The Polygon class enables you to treat the polygon as an object rather than having to deal with individual arrays.
To create a polygon object you can either create an empty polygon:
Polygon poly = new Polygon();
or create a polygon from a set of points using integer arrays, as in the previous example:
int exes[] = { 39,94,97,142,53,58,26 };

int whys[] = { 33,74,36,70,108,80,106 };

int pts = exes.length;

Polygon poly = new Polygon(exes,whys,pts);
Once you have a polygon object, you can append points to the polygon as you need to:
poly.addPoint(20,35);
Then, to draw the polygon, just use the polygon object as an argument to drawPolygon() or fillPolygon(). Here's that previous example, rewritten this time with a Polygon object. You'll also fill this polygon rather than just drawing its outline (Figure 9.8 shows the output):

Figure 9.8. Another polygon.

public void paint(Graphics g) {

    int exes[] = { 39,94,97,142,53,58,26 };

    int whys[] = { 33,74,36,70,108,80,106 };

    int pts = exes.length;

    Polygon poly = new Polygon(exes,whys,pts);

    g.fillPolygon(poly);

}

Ovals

Use ovals to draw ellipses or circles. Ovals are just like rectangles with overly rounded corners. You draw them using four arguments: the x and y of the top corner, and the width and height of the oval itself. Note that, because you're drawing an oval, the starting point is some distance to the left and up from the actual outline of the oval itself. Again, if you think of it as a rectangle, it's easier to place.
As with the other drawing operations, the drawOval() method draws an outline of an oval, and the fillOval() method draws a filled oval.
Here's an example of two ovals, a circle and an ellipse (Figure 9.9 shows how these two ovals appear on screen):

Figure 9.9.

public void paint(Graphics g) {

    g.drawOval(20,20,60,60);

    g.fillOval(120,20,100,60);

}

Arc

Of the drawing operations, arcs are the most complex to construct, which is why I saved them for last. An arc is a part of a oval; in fact, the easiest way to think of an arc is as a section of a complete oval. Figure 9.10 shows some arcs.

Figure 9.10.

The drawArc() method takes six arguments: the starting corner, the width and height, the angle at which to start the arc, and the degrees to draw it before stopping. Once again, there is a drawArc method to draw the arc's outline and the fillArc() to fill the arc. Filled arcs are drawn as if they were sections of a pie; instead of joining the two endpoints, both endpoints are joined to the center of the circle.
The important thing to understand about arcs is that you're actually formulating the arc as an oval and then drawing only some of that. The starting corner and width and height are not the starting point and width and height of the actual arc as drawn on the screen; they're the width and height of the full ellipse of which the arc is a part. Those first points determine the size and shape of the arc; the last two arguments (for the degrees) determine the starting and ending points.
Let's start with a simple arc, a C shape on a circle as shown in Figure 9.11.

Figure 9.11. A C arc.

To construct the method to draw this arc, the first thing you do is think of it as a complete circle. Then you find the x and y coordinates and the width and height of that circle. Those four values are the first four arguments to the drawArc() or fillArc() methods. Figure 9.12 shows how to get those values from the arc.

Figure 9.12. Constructing a circular arc.

To get the last two arguments, think in degrees around the circle. Zero degrees is at 3 o'clock, 90 degrees is at 12 o'clock, 180 at 9 o'clock, and 270 at 6 o'clock. The start of the arc is the degree value of the start of the arc. In this example, the starting point is the top of the C at 90 degrees; 90 is the fifth argument.
The sixth and last argument is another degree value indicating how far around the circle to sweep and the direction to go in (it's not the ending degree angle, as you might think). In this case, because you're going halfway around the circle, you're sweeping 180 degrees—and 180 is therefore the last argument in the arc. The important part is that you're sweeping 180 degrees counterclockwise, which is in the positive direction in Java. If you are drawing a backwards C, you sweep 180 degrees in the negative direction, and the last argument is —180. See Figure 9.13 for the final illustration of how this works.

Figure 9.13. Arcs on circles.


Note: It doesn't matter which side of the arc you start with; because the shape of the arc has already been determined by the complete oval it's a section of, starting at either endpoint will work.

Here's the code for this example; you'll draw an outline of the C and a filled C to its right, as shown in Figure 9.14:

Figure 9.14. Two circular arcs.

public void paint(Graphics g) {

   g.drawArc(20,20,60,60,90,180);

   g.fillArc(120,20,60,60,90,180);

}
Circles are an easy way to visualize arcs on circles; arcs on ellipses are slightly more difficult. Let's go through this same process to draw the arc shown in Figure 9.15.

Figure 9.15. An elliptical arc.

Like the arc on the circle, this arc is a piece of a complete oval, in this case, an elliptical oval. By completing the oval that this arc is a part of, you can get the starting points and the width and height arguments for the drawArc() or fillArc() method (Figure 9.16).

Figure 9.16.Arcs on ellipses.

Then, all you need is to figure out the starting angle and the angle to sweep. This arc doesn't start on a nice boundary such as 90 or 180 degrees, so you'll need some trial and error. This arc starts somewhere around 25 degrees, and then sweeps clockwise about 130 degrees (Figure 9.17).

Figure 9.17. Starting and ending points.

With all portions of the arc in place, you can write the code. Here's the Java code for this arc, both drawn and filled (note in the filled case how filled arcs are drawn as if they were pie sections):
public void paint(Graphics g) {

    g.drawArc(10,20,150,50,25,-130);

    g.fillArc(10,80,150,50,25,-130);

}
Figure 9.18 shows the two elliptical arcs.

Figure 9.18. Two elliptical arcs.

To summarize, here are the steps to take to construct arcs in Java:
  • Think of the arc as a slice of a complete oval.
  • Construct the full oval with the starting point and the width and height (it often helps to draw the full oval on the screen to get an idea of the right positioning).
  • Determine the starting angle for the beginning of the arc.
  • Determine how far to sweep the arc and in which direction (counterclockwise indicates positive values, clockwise indicates negative).

A Simple Graphics Example

Here's an example of an applet that uses many of the built-in graphics primitives to draw a rudimentary shape. In this case, it's a lamp with a spotted shade (or a sort of cubist mushroom, depending on your point of view). Listing 9.1 has the complete code for the lamp; Figure 9.19 shows the resulting applet.

Figure 9.19. The Lamp applet.

    Listing 9.1. The Lamp class.
  1: import java.awt.*;

 2: 

  3: public class Lamp extends java.applet.Applet {

 4: 

  5:    public void paint(Graphics g) {

  6:        // the lamp platform

  7:        g.fillRect(0,250,290,290);

 8:

  9:        // the base of the lamp

10:        g.drawLine(125,250,125,160);

11:        g.drawLine(175,250,175,160);

12: 

13:        // the lamp shade, top and bottom edges

14:         g.drawArc(85,157,130,50,-65,312);

15:         g.drawArc(85,87,130,50,62,58);

16: 

17:         // lamp shade, sides

18:         g.drawLine(85,177,119,89);

19:         g.drawLine(215,177,181,89);

20: 

21:         // dots on the shade

22:         g.fillArc(78,120,40,40,63,-174);

23:         g.fillOval(120,96,40,40);

24:         g.fillArc(173,100,40,40,110,180);

25:    }

26: }

Copying and Clearing

Once you've drawn a few things on the screen, you may want to move them around or clear the entire applet. The Graphics class provides methods for doing both these things.
The copyArea() method copies a rectangular area of the screen to another area of the screen. copyArea() takes six arguments: the x and y of the top corner of the rectangle to copy, the width and the height of that rectangle, and the distance in the x and y directions to which to copy it. For example, this line copies a square area 100 pixels on a side 100 pixels directly to its right:
g.copyArea(0,0,100,100,100,0);
To clear a rectangular area, use the clearRect() method. clearRect(), which takes the same four arguments as the drawRect() and fillRect() methods, fills the given rectangle with the current background color of the applet (you'll learn how to set the current background color later on today).
To clear the entire applet, you can use the size() method, which returns a Dimension object representing the width and height of the applet. You can then get to the actual values for width and height by using the width and height instance variables:
g.clearRect(0,0,size().width,size()height);

Text and Fonts

The Graphics class also enables you to print text on the screen, in conjunction with the Font class (and, sometimes, the FontMetrics class). The Font class represents a given font—its name, style, and point size—and FontMetrics gives you information about that font (for example, the actual height or width of a given character) so that you can precisely lay out text in your applet.
Note that the text here is drawn to the screen once and intended to stay there. You'll learn about entering text from the keyboard later on this week.

Creating Font Objects

To draw text to the screen, first you need to create an instance of the Font class. Font objects represent an individual font—that is, its name, style (bold, italic), and point size. Font names are strings representing the family of the font, for example, "TimesRoman", "Courier", or "Helvetica". Font styles are constants defined by the Font class; you can get to them using class variables—for example, Font.PLAIN, Font.BOLD, or Font.ITALIC. Finally, the point size is the size of the font, as defined by the font itself; the point size may or may not be the height of the characters.
To create an individual font object, use these three arguments to the Font class's new constructor:
Font f = new Font("TimesRoman", Font.BOLD, 24);
This example creates a font object for the TimesRoman BOLD font, in 24 points. Note that like most Java classes, you have to import this class before you can use it.
Font styles are actually integer constants that can be added to create combined styles; for example, Font.BOLD + Font.ITALIC produces a font that is both bold and italic.
The fonts you have available to you in your applets depend on which fonts are installed on the system where the applet is running. If you pick a font for your applet and that font isn't available on the current system, Java will substitute a default font (usually Courier). For best results, it's a good idea to stick with standard fonts such as "TimesRoman", "Helvetica", and "Courier".
You can also use the getFontList() method , defined in the java.awt.Tookit class to get a listing of the current fonts available on the system, and make choices about which fonts to use on the fly. See the API documentation for that method if you're interested in trying this.

Drawing Characters and Strings

With a font object in hand, you can draw text on the screen using the methods drawChars() and drawString(). First, though, you need to set the current font to your font object using the setFont() method.
The current font is part of the graphics state that is kept track of by the Graphics object on which you're drawing. Each time you draw a character or a string to the screen, that text is drawn using the current font. To change the font of the text, first change the current font. Here's a paint() method that creates a new font, sets the current font to that font, and draws the string "This is a big font.", at the point 10,100.
public void paint(Graphics g) {

    Font f = new Font("TimesRoman", Font.PLAIN, 72);

    g.setFont(f);

    g.drawString("This is a big font.", 10, 100);

}
This should all look familiar to you; this is how the Hello World and Hello Again applets throughout this book were produced.
The latter two arguments to drawString() determine the point where the string will start. The x value is the start of the leftmost edge of the text; y is the baseline for the entire string.
Similar to drawString() is the drawChars() method that, instead of taking a string as an argument, takes an array of characters. drawChars() has five arguments: the array of characters, an integer representing the first character in the array to draw, another integer for the last character in the array to draw (all characters between the first and last are drawn), and the x and y for the starting point. Most of the time, drawString() is more useful than drawChars().
Listing 9.2 shows an applet that draws several lines of text in different fonts; Figure 9.20 shows the result.

Figure 9.20. The output of the ManyFonts applet.

    Listing 9.2. Many different fonts.
 1: import java.awt.Font;

 2: import java.awt.Graphics;

 3:

 4: public class ManyFonts extends java.applet.Applet {

 5:

 6:    public void paint(Graphics g) {

 7:        Font f = new Font("TimesRoman", Font.PLAIN, 18);

 8:        Font fb = new Font("TimesRoman", Font.BOLD, 18);

 9:        Font fi = new Font("TimesRoman", Font.ITALIC, 18);

10:        Font fbi = new Font("TimesRoman", Font.BOLD + Font.ITALIC, 18);

11:

12:        g.setFont(f);

13:        g.drawString("This is a plain font", 10, 25);

14:        g.setFont(fb);

15:        g.drawString("This is a bold font", 10, 50);

16:        g.setFont(fi);

17:        g.drawString("This is an italic font", 10, 75);

18:        g.setFont(fbi);

19:        g.drawString("This is a bold italic font", 10, 100);

20:    }

21:

22: }

Finding Out Information About a Font

Sometimes, you may want to make decisions in your Java program based on the qualities of the current font—for example, its point size, or the total height of its characters. You can find out some basic information about fonts and font objects by using simple methods on Graphics and on the Font objects. Table 9.1 shows some of these methods:
    Table 9.1. Font methods.
Method Name

In Object

Action

getFont()Graphics Returns the current font object as previously set by setFont()
getName()FontReturns the name of the font as a string
getSize()FontReturns the current font size (an integer)
getStyle()FontReturns the current style of the font (styles are integer constants: 0 is plain, 1 is bold, 2 is italic, 3 is bold italic)
isPlain()FontReturns true or false if the font's style is plain
isBold()FontReturns true or false if the font's style is bold


isItalic()


Font


Returns true or false if the font's style is italic
For more detailed information about the qualities of the current font (for example, the length or height of given characters), you need to work with font metrics. The FontMetrics class describes information specific to a given font: the leading between lines, the height and width of each character, and so on. To work with these sorts of values, you create a FontMetrics object based on the current font by using the applet method getFontMetrics():
Font f = new Font("TimesRoman", Font.BOLD, 36);

FontMetrics fmetrics = getFontMetrics(f);

g.setfont(f);
Table 9.2 shows some of the things you can find out using font metrics. All these methods should be called on a FontMetrics object.
    Table 9.2. Font metrics methods.
Method Name

Action

stringWidth(string)Given a string, returns the full width of that string, in pixels
charWidth(char)Given a character, returns the width of that character
getAscent()Returns the ascent of the font, that is, the distance between the font's baseline and the top of the characters
getDescent()Returns the descent of the font—that is, the distance between the font's baseline and the bottoms of the characters (for characters such as p and q that drop below the baseline)
getLeading()Returns the leading for the font, that is, the spacing between the descent of one line and the ascent of another line


getHeight()


Returns the total height of the font, which is the sum of the ascent, descent, and leading value
As an example of the sorts of information you can use with font metrics, Listing 9.3 shows the Java code for an applet that automatically centers a string horizontally and vertically inside an applet. The centering position is different depending on the font and font size; by using font metrics to find out the actual size of a string, you can draw the string in the appropriate place.
Note the applet.size() method here, which returns the width and height of the overall applet area as a Dimension object. You can then get to the individual width and height by using the width and height instance variables.
Figure 9.21 shows the result (less interesting than if you actually compile and experiment with various applet and font sizes).

Figure 9.21. The centered text.

    Listing 9.3. Centering a string.
 1: import java.awt.Font;

 2: import java.awt.Graphics;

 3: import java.awt.FontMetrics;

 4:

 5: public class Centered extends java.applet.Applet {

 6:

 7:    public void paint(Graphics g) {

 8:        Font f = new Font("TimesRoman", Font.PLAIN, 36);

 9:        FontMetrics fm = getFontMetrics(f);

10:        g.setFont(f);

11:

12:        String s = "This is how the world ends.";

13:        int xstart = (size().width - fm.stringWidth(s)) / 2;

14:        int ystart = (size().height + fm.getHeight()) / 2;

15:

16:        g.drawString(s, xstart, ystart);

17:    }

18:}

Color

Drawing black on a gray background is all very nice, but being able to use different colors is much nicer. Java provides methods and behaviors for dealing with color in general through the Color class, and also provides methods for setting the current foreground and background colors so that you can draw with the colors you created.
Java's abstract color model uses 24-bit color, wherein a color is represented as a combination of red, green, and blue values. Each component of the color can have a number between 0 and 255. 0,0,0 is black, 255,255,255 is white, and Java can represent millions of colors between as well.
Java's abstract color model maps onto the color model of the platform Java is running on, which usually has only 256 colors or fewer from which to choose. If a requested color in a color object is not available for display, the resulting color may be mapped to another or dithered, depending on how the browser viewing the color implemented it, and depending on the platform on which you're running. In other words, although Java gives the capability of managing millions of colors, very few may actually be available to you in real life.

Using Color Objects

To draw an object in a particular color, you must create an instance of the Color class to represent that color. The Color class defines a set of standard color objects, stored in class variables, that enable you quickly to get a color object for some of the more popular colors. For example, Color.red gives you a Color object representing red (RGB values of 255, 0, and 0), Color.white gives you a white color (RGB values of 255, 255, and 255), and so on. Table 9.3 shows the standard colors defined by variables in the Color class.
    Table 9.3. Standard colors.
Color Name

RGB Value

Color.white255,255,255
Color.black0,0,0
Color.lightGray192,192,192
Color.gray128,128,128
Color.darkGray64,64,64
Color.red255,0,0
Color.green0,255,0
Color.blue0,0,255
Color.yellow255,255,0
Color.magenta255,0,255
Color.cyan0,255,255
Color.pink255,175,175


Color.orange


255,200,0
If the color you want to draw in is not one of the standard color objects, fear not. You can create a color object for any combination of red, green, and blue, as long as you have the values of the color you want. Just create a new color object:
Color c = new Color(140,140,140);
This line of Java code creates a color object representing a dark grey. You can use any combination of red, green, and blue values to construct a color object.
Alternatively, you can also create a color object using three floats from 0.0 to 1.0:
Color c = new Color(0.55,0.55,0.55)

Testing and Setting the Current Colors

To draw an object or text using a color object, you have to set the current color to be that color object, just as you have to set the current font to the font in which you want to draw. Use the setColor() method (a method for Graphics objects) to do this:
g.setColor(Color.green);
After setting the current color, all drawing operations will occur in that color.
In addition to setting the current color for the graphics context, you can also set the background and foreground colors for the applet itself by using the setBackground() and setForeground() methods. Both of these methods are defined in the java.awt.Component class, which Applet—and therefore your classes—automatically inherits.
The setBackground() method sets the background color of the applet, which is usually a grey. It takes a single argument, a color object:
setBackground(Color.white);
The setForeground() method also takes a single color as an argument, and affects everything that has been drawn on the applet, regardless of the color in which it has been drawn. You can use setForeground() to change the color of everything in the applet at once, rather than having to redraw everything:
setForeground(Color.black);
In addition to the setColor(), setForeground(), and setBackground() methods, there are corresponding "get" methods that enable you to retrieve the current graphics color, background, or foreground. Those methods are getColor() (defined in Graphics objects), getForeground() (defined in Applet), and getBackground() (also in Applet). You can use these methods to choose colors based on existing colors in the applet:
setForeground(g.getColor());

A Single Color Example

Listing 9.4 shows the code for an applet that fills the applet's drawing area with square boxes, each of which has a randomly chosen color in it. It's written so that it can handle any size of applet and automatically fill the area with the right number of boxes.
    Listing 9.4. Random color boxes.
 1:  import java.awt.Graphics;

 2:  import java.awt.Color;

 3:

 4:  public class ColorBoxes extends java.applet.Applet {

 5:

 6:      public void paint(Graphics g) {

 7:          int rval, gval, bval;

 8:

 9:          for (int j = 30; j < (size().height -25); j += 30)

10:             for (int i = 5; i < (size().width -25); i += 30) {

11:                 rval = (int)Math.floor(Math.random() * 256);

12:                 gval = (int)Math.floor(Math.random() * 256);

13:                 bval = (int)Math.floor(Math.random() * 256);

14:

15:                 g.setColor(new Color(rval,gval,bval));

16:                 g.fillRect(i, j, 25, 25);

17:                 g.setColor(Color.black);

18:                 g.drawRect(i-1, j-1, 25, 25);

19:             }

20:     }

21: }
The two for loops are the heart of this example; the first one draws the rows, and the second draws the individual boxes within the row. When a box is drawn, the random color is calculated first, and then the box is drawn. A black outline is drawn around each box, because some of them tend to blend into the background of the applet.
Because this paint method generates new colors each time the applet is painted, you can regenerate the colors by moving the window around or by covering the applet's window with another one. Figure 9.22 shows the final applet (although given that this picture is black and white, you can't get the full effect of the multicolored squares).

Figure 9.22. The random colors applet.

Summary

You present something on the screen by painting inside your applet: shapes, graphics, text, or images. Today, you learned the basics of how to paint, including using the graphics primitives to draw rudimentary shapes, using fonts and font metrics to draw text, and using Color objects to change the color of what you're drawing on the screen. It's this foundation in painting that enables you to do animation inside an applet (which basically involves just painting repeatedly to the screen) and to work with images. These are topics you'll learn about tomorrow.

Q&A


Q: In all the examples you show, and in all the tests I've made, the graphics primitives, such as drawLine() and drawRect(), produce lines that are one pixel wide. How can I draw thicker lines?

A: In the current state of the Java Graphics class, you can't; no methods exist for changing the default line width. If you really need a thicker line, you have to draw multiple lines one pixel apart to produce that effect.
Q: I wrote an applet to use Helvetica. It worked fine on my system, but when I run it on my friend's system, everything is in Courier. Why?
A: Your friend most likely doesn't have the Helvetica font installed on his or her system. When Java can't find a font, it substitutes a default font instead—in your case, Courier. The best way to deal with this is to query the font list using the getFontList() method in the java.awt.Tookit class.
Q: I tried out that applet that draws boxes with random colors, but each time it draws, a lot of the boxes are the same color. If the colors are truly random, why is it doing this?
A: Two reasons. The first is that the random number generator I used in that code (from the Math class) isn't a very good random number generator; in fact, the documentation for that method says as much. For a better random number generator, use the Random class from the java.util package.

The second, more likely, reason is that there just aren't enough colors available in your browser or on your system to draw all the colors that the applet is generating. If your system can't produce the wide range of colors available using the Color class, or if the browser has allocated too many colors for other things, you may end up with duplicate colors in the boxes, depending on how the browser and the system has been written to handle that. Usually your ap

No comments:

Post a Comment