A picture is worth a thousand wordsa good graphic maybe more. And, if you're talking download time, certainly less time-consuming than a JPEG file. For the remainder of this week, you'll learn the sorts of things you can do with the built-in Java
class libraries, and how you can combine them to produce interesting effects. You'll start today with learning how to produce lines and shapes using the built-in graphics primitives, how to print text using fonts, and how to use and modify color in your
applets. Today, you'll specifically learn:
Today's lesson discusses many of the basic graphics, fonts, and color operations made available to you by the Java class library. However, today's lesson is intended to be an introduction and an overview more than an exhaustive description of all the features available. Be sure to check out the Java API documentation for more information on the classes described today.
With Java's graphics capabilities, you can draw lines, shapes, characters, and display images to the screen inside the applet window. You'll find that most of the graphics operations in Java are methods defined in the Graphics class. As a bonus, you
don't have to create an instance of Graphics in order to draw something in your applet. An applet's paint() method (which you learned about yesterday) gives you a Graphics object. By using that object, results appear in the browser.
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 { ... }
To draw an object on the screen, you call one of the drawing methods available in the Graphics class. All of the drawing methods have arguments that represent endpoints, corners, or starting locations of the object. These arguments are passed as values
in the applet's coordinate system, for example, a line starting at the point 10,10 and ending 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 10.1 shows how you might draw a
simple square by using this coordinate system.
Figure 10.1. Drawing a square using 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 might take some practice to become familiar with it.
Remember also, that these coordinates are relative to your applets embedded window space inside the browser, and not the browser or screen as a whole.
The Graphics class provides a set of simple built-in graphics primitives for drawing. These primitives include lines, rectangles, polygons, ovals, and arcs.
Bitmap images, such as JPEG and GIF files, can also be drawn by using the Graphics class. You'll learn about this tomorrow.
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 10.2 shows the result of this fragment of code.
The Java graphics primitives provide not just one, but three kinds of rectangles:
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 10.3 shows the result.)
public void paint(Graphics g) { g.drawRect(20,20,60,60); g.fillRect(120,20,60,60); }
Figure 10.3. An outline rectangle and a filled rectangle.
To draw a rectangle with rounded corners, the drawRoundRect() and fillRoundRect() methods are used. Drawing rounded rectangles is similar to regular rectangles, except that rounded rectangles have two extra arguments. These two extra arguments supply
the width and height values of the corner angles and also specify the starting point of the arc along the edges of the rectangle. The first argument describes the angle along the horizontal plane, the second describes the angle along the vertical plane.
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 10.4 shows some examples of rounded corners.
Figure 10.4. Some rectangles with 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 10.5 shows the resulting squares.)
public void paint(Graphics g) { g.drawRoundRect(20,20,60,60,10,10); g.fillRoundRect(120,20,60,60,20,20); }
Figure 10.5. Two rectangles with rounded corners.
The final rectangle primitive creates three-dimensional rectangles. These rectangles aren't really 3D; if they were, you could make them pop-out of the screen and bop somebody in the head. Instead, they have a shadow effect that makes them appear
either raised or indented from the surface of the applet. Three-dimensional rectangles have five argumentsfour arguments are for the x and y start position and the width and height of the rectangle, and 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 two different methods to draw (draw3DRect()) and fill (fill3DRect()). Here's a code fragment to produce an indented and a raised 3D
rectangle. (Figure 10.6 shows the result.)
public void paint(Graphics g) { g.draw3DRect(20,20,60,60,true); g.draw3DRect(120,20,60,60,false); }
Figure 10.6. A raised rectangle and an indented rectangle.
Due to the very small line width in the current version of Visual J++, it is very difficult to see the 3D effect on 3D rectangles. If you seem to be having trouble with 3D rectangles, this might be why. Try drawing 3D rectangles using a color other than black. Sometimes this makes them easier to see.
Polygons are shapes with multiple sides. In order to draw a polygon, you need sets of x and y coordinates. The drawing method starts at one xy set and draws a line to the second; it continues on from there and draws a line to the third xy set, and so
on, until all the xy sets have been drawn.
As with rectangles, you can draw an outline or a filled polygon (using the drawPolygon() and fillPolygon() methods, respectively). When specifying the list of xy coordinates to the method, you have a choice of indicating them as either arrays of x and
y coordinates or as an instance of the Polygon class.
Using the array method, the drawPolygon() and fillPolygon() methods take three arguments:
The x and y arrays must, of course, have the same number of elements.
The following is an example of drawing an outline polygon by using the array method. (Figure 10.7 shows the result.)
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); }
Figure 10.7. An outline polygon using arrays to specify the x and y points.
Java does not automatically close an outline polygon. If you want to complete the outline shape, you have to include the starting xy points of the polygon as the last elements of the arrays. When you're drawing a filled polygon, however, Java does
automatically join 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 an existing polygon or if you're building a polygon on the fly. The Polygon class enables you to treat the
polygon as an object rather than having to deal with the 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(). The following is the array example, rewritten using, instead, a Polygon object. Note that this code fragment fills the polygon, rather than just
drawing its outline. (Figure 10.8 shows the output.)
public void paint(Graphics g) { int iExes[] = { 39,94,97,142,53,58,26 }; int iWhys[] = { 33,74,36,70,108,80,106 }; int iPts = iExes.length; Polygon poly = new Polygon(iExes,iWhys,iPts); g.fillPolygon(poly); }
Figure 10.8. A filled polygon using the Polygon() object.
Use ovals to draw ellipses or circles. Think of ovals as 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. When you specify the top corner, it's
actually a point outside the oval. If you think back to high school geometry of drawing an ellipse inside a rectangle, drawing an oval using the drawOval() method is quite similar.
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 10.9 shows how these two ovals appear on the screen.)
public void paint(Graphics g) { g.drawOval(20,20,60,60); g.fillOval(120,20,100,60); }
Figure 10.9. A circle and an oval.
Of all the drawing operations, arcs are possibly the most complex to construct, which is why they're the last example. An arc is a part of an oval; in fact, the easiest way to think of an arc is as a section of a complete oval. Figure 10.10 shows some
arcs.
The drawArc() method takes six arguments: the x and y coordinates of the starting corner, the width and height, the starting angle of the arc, and the number of degrees to draw it before stopping. Once again, there is a drawArc method to draw the arc's
outline and the fillArc() method 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.
An important thing to understand about arcs is that you're actually formulating the arc as an oval and then drawing only some of it. The starting corner and width and height are not actually what's drawn on the screen as the arc; they're the width and
height of the full ellipse of which the arc is only a part. Those first four arguments determine the size and shape of the arc; the last two arguments (for the degrees) determine the starting and ending points.
You'll start with a simple arc, a C shape on a circle as shown in Figure 10.11.
Figure 10.11. A C shape on a circle.
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 of the drawArc() or
fillArc() methods. Figure 10.12 shows how to get those values from the arc.
Figure 10.12. Getting the x and y coordinates and width and height of a circle.
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. In this example, the starting point of the arc is the top of the C at 90 degrees; 90
then, is the fifth argument.
The sixth and last argument is another degree value indicating how far around the circle the arc sweeps and the direction to follow. (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 the positive direction in Java. (Note that if you are drawing a backwards C, you sweep 180
degrees in the negative direction, and the last argument is -180.) See Figure 10.13 for the final illustration of how this works.
Figure 10.13. An arc with a C.
It doesn't really matter which side of the arc you start at; 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 10.14:
public void paint(Graphics g) { g.drawArc(20,20,60,60,90,180); g.fillArc(120,20,60,60,90,180); }
Figure 10.14. An outline C and a filled C.
Arcs on ellipses are slightly more difficult than arcs on circles, but they use the same process. Now go through this same process to draw the arc shown in Figure 10.15.
Figure 10.15. An arc on an ellipse.
Like the arc on the circle example, 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. (See Figure 10.16.)
Figure 10.16. An elliptical oval.
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 like the circle, so you'll need a protractor. This arc starts somewhere around 25 degrees, and then
sweeps clockwise about 130 degrees. (See Figure 10.17.)
Figure 10.17. An arc on an elliptical oval.
With all portions of the arc in place, you can write the code. Here's the Java code for this arc, using both the draw and fill methods. Note 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 10.18 shows the two elliptical arcs.
Figure 10.18. Two elliptical arcs (outline and filled).
To summarize, here are the steps to construct arcs in Java:
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, depending upon your point of view, a sort of cubist mushroom). Listing 10.1 has the
complete code for the lamp; Figure 10.19 shows the resulting applet.
Listing 10.1. The Lamp class.
1: import java.awt.*; 2: 3: public class Lamp extends java.applet.Applet 4: { 5: 6: public void paint(Graphics g) 7: { 8: // the lamp platform 9: g.fillRect(0,250,290,290); 10: 11: // the base of the lamp 12: g.drawLine(125,250,125,160); 13: g.drawLine(175,250,175,160); 14: 15: // the lamp shade, top and bottom edges 16: g.drawArc(85,157,130,50,-65,312); 17: g.drawArc(85,87,130,50,62,58); 18: 19: // lamp shade, sides 20: g.drawLine(85,177,119,89); 21: g.drawLine(215,177,181,89); 22: 23: // dots on the shade 24: g.fillArc(78,120,40,40,63,-174); 25: g.fillOval(120,96,40,40); 26: g.fillArc(173,100,40,40,110,180); 27: } 28: }
Figure 10.19. The lamp applet.
Once you've drawn a few things on the screen, you might want to move them around or clear the applet window. The Graphics class provides methods for doing both of 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 coordinates of the top corner of the rectangle to copy, the width and height of the rectangle, and the position to
copy it to x and y coordinates. For example, the following line of code copies an area 100 pixels square to a position 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 window, 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 data members:
g.clearRect(0,0,size().width,size().height);
The Graphics class, in conjunction with the Font and FontMetrics classes, enables you to print text on the screen. The Font class represents a given fontits name, style, and point sizeand FontMetrics gives you information about a font (for
example, the actual height or width of a given character) so that you can lay out text in your applet with better precision.
The text here is drawn to the screen once and intended to stay there. You'll learn about letting users enter text from the keyboard later on this week.
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 might or might not be the height of the characters.
To create an individual font object, use these three arguments to the Font class' new constructor:
Font f = new Font("TimesRoman", Font.BOLD, 24);
This example creates a font object for the "TimesRoman" BOLD font, in 24 points. Remember 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 available to your applet depend upon the fonts installed on the system where the applet is running. If the font you use in your applet isn't available on the user's system, Java will substitute a default font (usually Courier). To be
compatible with all systems accessing your applet through the Internet, it's a good idea to stick with the standard fonts such as "TimesRoman", "Helvetica", and "Courier". If you'll be publishing your applet on an intranet,
you'll probably have a wider variety of standard fonts to work with; check your system documentation to see which common fonts would be available on all platforms. Also, Microsoft's ActiveX components allow you to use TrueType fonts (more on that when you
do ActiveX).
Your applet can also determine and use fonts on the fly; be careful, thoughplan and test thoroughly. To do this, you use the getFontList() method, defined in the java.awt.Toolkit class. It returns a list of the fonts available on the user's
system, from which you can perform some comparison checking and then make choices about which fonts to use. See the InfoView getFontList() and getFontMetrics topics if you're interested in trying this.
With a font object in hand, you can draw text on the screen using the methods drawChars() and drawString(). Before using either of these, you need to use the setFont() method to set the current font to your font object.
The current font is part of the graphics state that is kept track of by the active Graphics object. Each time you draw a character or a string to the screen, that text is drawn using the current font. To change to a different font, first change the
current font. Here's a paint() method that creates a new font object, sets the current font to the one from the object, and then draws the string "This is a big font.", at the point 10,100 using the new current font.
public void paint(Graphics g) { Font f = new Font("TimesRoman", Font.PLAIN, 72); g.setFont; g.drawString("This is a big font.", 10, 100); }
If this looks familiar to you, it should. This is how the Hello World and Hello Again applets drew text to the applet window.
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.
Baseline is a typographic term. It refers to the common horizontal line on which all characters rest. A character (or parts of) ascend above the baseline; with characters such as g, j, p, q, and y, parts of the character
descend below the baseline. Also, some very decorative or cursive fonts might have descenders (tails) for all of the characters in the font.
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 10.2 shows an applet that draws several lines of text in different fonts; Figure 10.20 shows the result.
Listing 10.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: { 8: Font f = new Font("TimesRoman", Font.PLAIN, 18); 9: Font fb = new Font("TimesRoman", Font.BOLD, 18); 10: Font fi = new Font("TimesRoman", Font.ITALIC, 18); 11: Font fbi = new Font("TimesRoman", Font.BOLD + Font.ITALIC, 18); 12: 13: g.setFont; 14: g.drawString("This is a plain font", 10, 25); 15: g.setFont(fb); 16: g.drawString("This is a bold font", 10, 50); 17: g.setFont(fi); 18: g.drawString("This is an italic font", 10, 75); 19: g.setFont(fbi); 20: g.drawString("This is a bold italic font", 10, 100); 21: } 22: 23: }
Figure 10.20. The output of the ManyFonts applet.
Sometimes, you might 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 10.1 shows some of these methods:
Method Name | In Object | Action |
getFont() | Graphics | Returns the current font object as previously set by setFont() |
getName() | Font | Returns the name of the font as a string |
getSize() | Font | Returns the current font size (an integer) |
getStyle() | Font | Returns the current style of the font (styles are integer constants: 0 is plain, 1 is bold, 2 is italic, 3 is bold italic) |
isPlain() | Font | Returns true or false if the font's style is plain |
isBold() | Font | Returns 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; g.setfont;
Table 10.2 shows some of the things you can find out using font metrics. All these methods should be called on a FontMetrics object.
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 fontthat is, the distance between the font's baseline and the top of the characters |
getDescent() | Returns the descent of the fontthat is, the distance between the font's baseline and the bottom of the characters (for characters such as p and q that drop below the baseline) |
getLeading() | Returns the leading for the fontthat 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 10.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 data members.
Listing 10.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: 8: public void paint(Graphics g) 9: { 10: Font f = new Font("TimesRoman", Font.PLAIN, 36); 11: FontMetrics fm = getFontMetrics; 12: g.setFont; 13: 14: String s = "This is how the world ends."; 15: int xstart = (size().width - fm.stringWidth(s)) / 2; 16: int ystart = (size().height + fm.getHeight()) / 2; 17: 18: g.drawString(s, xstart, ystart); 19: } 20:}
Figure 10.21 shows the result (less interesting than if you actually compile and experiment with various applet and font sizes).
Figure 10.21. The centered text.
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 to the color model of the platform on which Java is running. The user's platform might have 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 on the user's system might be mapped to another color or dithered. The resulting color depends upon how the color map was implemented by the browser. In other words, although Java provides the capability of managing millions of colors, in
reality very few colors might actually be available to the user.
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 to quickly 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 10.3 shows the standard colors defined by
class variables in the Color class.
Color Name | RGB Value |
Color.white | 255,255,255 |
Color.black | 0,0,0 |
Color.lightGray | 192,192,192 |
Color.gray | 128,128,128 |
Color.darkGray | 64,64,64 |
Color.red | 255,0,0 |
Color.green | 0,255,0 |
Color.blue | 0,0,255 |
Color.yellow | 255,255,0 |
Color.magenta | 255,0,255 |
Color.cyan | 0,255,255 |
Color.pink | 255,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 gray. 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);
Just as you have to set the current font to the font with which you want to draw, to draw an object or text using a color object, you have to set the current color for the graphics context to be that color object. This allows you to set different
colors for different objects. Use the setColor() method (a method for Graphics objects) to do this:
g.setColor(Color.green);
The Graphics Context refers to the current settings of the active Java window. The Graphics Context includes font, background color, foreground color, and so on.
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 Appletand therefore, your classesautomatically inherits.
The setBackground() method sets the background color of the applet, which is usually defaulted to gray by the user's browser. 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 already been drawn by the applet, regardless of the color in which it had been originally 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, background, and foreground colors. 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());
Listing 10.4 shows the code for an applet that fills the applet's drawing area with square boxes, each of which is filled with a randomly chosen color. It's written so that it can handle any size applet and automatically populate the area with the
right number of boxes.
Listing 10.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: 7: public void paint(Graphics g) 8: { 9: int rval, gval, bval; 10: 11: for (int j = 30; j < (size().height -25); j += 30) 12: { 13: for (int i = 5; i < (size().width -25); i += 30) 14: { 15: rval = (int)Math.floor(Math.random() * 256); 16: gval = (int)Math.floor(Math.random() * 256); 17: bval = (int)Math.floor(Math.random() * 256); 18: g.setColor(new Color(rval,gval,bval)); 19: g.fillRect(i, j, 25, 25); 20: g.setColor(Color.black); 21: g.drawRect(i-1, j-1, 25, 25); 22: } 23: } 24: } 25: }
The two for loops are the heart of this example; the first one draws the rows, and the second draws the individual boxes within each row. When a box is drawn, the random color is calculated first, and then the box is drawn. Because some boxes tend to
blend into the background of the applet, a black outline is drawn around each box.
Because the 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 10.22 shows the final applet (although the multicolored
squares might be difficult to visualize in the picture shown).
Figure 10.22. The random colors applet.
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, which you'll learn about tomorrow when the topic of discussion is animation.
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 works 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 insteadin your case, Courier. The best way to deal with this is to query the font list
using the getFontList() method in the java.awt.Toolkit class, and then use a font in the same font family as Helvetica.
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: There are two reasons. The first is that the random number generator we 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 might end up with duplicate colors in the boxes. Remember, this behavior (for you and any potential user) is dependent upon how the system colors are set (16, 256, 64k, 16
million, and so on) and the browser implementation of the color mapper.