Chapter 9 - Graphics
The Graphics class allows you to draw shapes, display images, and manipulate the results. The coordinate system used in Java is similar to most in that the origin (0, 0) is located at the top left corner. From there the x values grow to the right and the y values grow to the bottom. The numbers correspond to pixels on the screen.
Drawing
Drawing refers to the act of painting simple lines and shapes on your applet. Lines are drawn using the drawLine() method defined in the Graphics class. The method takes four integers as arguments which are the starting x,y position and ending x,y position. There is no way to change the width of the line that the applet will draw. To accomplish this effect you could draw multiple lines next to each other.
public void paint(Graphics g) { g.drawLine(10,10,50,50); g.drawLine(10,10,50,30); g.drawLine(10,10,50,70); }Rectangles can be drawn normally or filled in with the selected color. Each type uses a different method but has similar arguments. The arguments are four integers which specify the starting x,y position and the width,height. The drawRect() method is used for normal outline rectangles and the fillRect() method is used for filled rectangles.
public void paint(Graphics g) { g.drawRect(10,10,50,50); g.fillRect(70,10,70,50); }Three-dimensional rectangles are drawn in a similar method but the method has an extra argument. This boolean argument specifies whether the 3D rectangle should be indented or raised. True corresponds to a raised rectangle and false to an indented one.
public void paint(Graphics g) { g.draw3DRect(10,10,50,50,false); g.draw3DRect(70,10,130,50,true); }Rounded rectangles are rectangles that have rounded corners. These can also be drawn in outline or in a filled manner. The first four integer arguments serve the same purpose as the previous examples and the last two integer arguments determine the width and height of the rounding effect. The values are how far along the edge the rounding should travel.
public void paint(Graphics g) { g.drawRoundRect(10,10,50,50,10,10); g.drawRoundRect(70,10,70,50,20,7); g.fillRoundRect(150,10,40,70,5,15); }Ovals are drawn using the same arguments as rectangles but the edges are completely rounded. The first two arguments specify the top left corner of the virtual box the oval will be drawn in and the second two arguments specify the bottom right corner. Again there are two methods depending on whether you want a filled oval or a normal oval.
public void paint(Graphics g) { g.drawOval(10,10,50,50); g.fillOval(70,10,70,50); }Polygons are shapes that consist of a series of lines. They can be filled or not filled and take a sequence of x,y coordinates to draw. The filled polygons are first closed, meaning that a line is drawn from the end point to the start point, and then areas are filled with color. There are two different ways to call the polygon methods. The first takes an array of x positions, an array of y positions, and an integer corresponding to the number of points (the length of the two arrays and the third argument should all be equal). The other option is to create an instance of the Polygon class and pass that to the drawing method. You can add points to a polygon by using the addPoint(x,y) method.
public void paint(Graphics g) { int xPoints[] = {10,50,50,10,25}; int yPoints[] = {10,50,10,50,75}; int numPoints = xPoints.length; int x2Points[] = {70,110,110,70,85}; int y2Points[] = {10,50,10,50,75}; int num2Points = x2Points.length; Polygon mess = new Polygon(x2Points, y2Points, num2Points); g.drawPolygon(xPoints, yPoints, numPoints); g.fillPolygon(mess); }Arcs are basically pieces of ovals. They take two extra arguments that help specify which piece of the oval to keep. The last two arguments are integers that specify the starting and distance angles, specified in degrees from center right. The distance angle determines how much of the arc should be kept starting from the starting angle and can take negative values. The normal and filled methods are available. When using the filled arc method the area that would be swept out by the arc is filled in.
public void paint(Graphics g) { g.drawArc(10,10,50,70,135, -225); g.drawArc(70,10,70,50,0,270); g.fillArc(150,10,90,70,180,110); }
Color
Color allows you to break free from the black and gray with which you have become accustomed. You can set the current foreground and background colors to manipulate the look of your applet. Java is capable of addressing millions of colors (24 bit) but the enclosing browser or operating system usually limits the number to 256 (8 bit). This means many of your colors may be mapped to other colors or dithered to represent a similar color.
Colors are specified in the red, green, blue method (RGB). Each color can take a value from 0 to 255. You can alternatively use floats which would takes values from 0.0 to 1.0 or a single integer where bits 0-7 are blue, bits 8-15 are green, and bits 16-23 are red. The larger the value the more of that specific color is thrown into the mix. Java has defined a series of class variables of common colors that you can use. I have provided the RGB values for example purposes
Color.black RGB value of 0,0,0 Color.blue RGB value of 0,0,255 Color.cyan RGB value of 0,255,255 Color.darkGray RGB value of 64,64,64 Color.gray RGB value of 128,128,128 Color.green RGB value of 0,255,0 Color.lightGray RGB value of 192,192,192 Color.magenta RGB value of 255,0,255 Color.orange RGB value of 255,200,0 Color.pink RGB value of 255,175,175 Color.red RGB value of 255,0,0 Color.white RGB value of 255,255,255 Color.yellow RGB value of 255,255,0Creating your own colors will take some practice and usually involves trial and error. Here are some more subtle colors.
Color slateBlue = new Color(80,124, 224); Color lightSlateBlue = new Color(167,191,246); Color deepMaroon = new Color(188,54,108); Color brickRed = new Color(158,26,26); Color lightPink = new Color(255,154,202);To draw objects in a certain color you need to first set the current color to the wanted value. Then any objects you draw after the color has been set will appear in that color until it is again set to another color.
g.setColor(Color.magenta);You can also set the background and foreground colors which affect the entire applet. The setBackground() method changes the color in the background of the applet which is by default a medium gray. The setForegroud() method changes the color that every object is drawn in. This is used to change the color of all objects at once rather than having to set the color and redraw every object separately.
setBackground(Color.white); setForeground(Color.blue);You can test the current colors that are being used by the applet. The getColor(), getForeground(), and getBackground() methods return the color that is being used in each context.
Many common graphics applications, such as Adobe Photoshop, can be used to create the color values interactively. The Color Chooser applet is a small example that will help you try out different colors interactively. This is not a very robust example because it does not check the input to make sure it is an integer between 0 and 255. Values that do not make sense are ignored and quietly produce an error. Nevertheless, this applet may be helpful.
import java.applet.*; import java.awt.*; import java.awt.Graphics; import java.awt.Color; public class ColorChooser extends Applet { TextField redValue = new TextField("0",3); TextField greenValue = new TextField("0",3); TextField blueValue = new TextField("0",3); Color boxColor = new Color(0,0,0); public void init() { resize(100, 250); setLayout(new FlowLayout(FlowLayout.RIGHT)); add(new Label("Red")); add(redValue); add(new Label("Green")); add(greenValue); add(new Label("Blue")); add(blueValue); add(new Button("Try Color")); } public boolean action(Event e, Object arg) { if (e.target instanceof Button) changeColor(); repaint(); return true; } public void changeColor() { String redTemp = redValue.getText(); String greenTemp = greenValue.getText(); String blueTemp = blueValue.getText(); int redNumber = Integer.parseInt(redTemp); int greenNumber = Integer.parseInt(greenTemp); int blueNumber = Integer.parseInt(blueTemp); boxColor = new Color(redNumber,greenNumber,blueNumber); } public void paint(Graphics g) { g.setColor(boxColor); g.fillRect(10,150,90,230); } }
Fonts
You have previously seen the drawString() which allows you to draw a string in your applet, but you were unable to change the size, style, or type of font you used. The Font and Font metrics classes allow you to change the look of the text and to get information that will help you lay out text accurately in your applet.
An instance of the Font class stores information on the type of font, its style, and its size. Types of fonts are described by their family name such as "TimesRoman", "Palatino", or "Courier". The style argument is an integer but there is a series of class variables defined to help you select the correct ones.
Font.PLAIN plain style Font.BOLD bold style Font.ITALIC italic styleSince these attributes are integers, you can add them to create the composite style of bold and italic by using Font.BOLD + Font.Italic. The point size determines the size of the font to be displayed.
Font bigBoldCourier = new Font("Courier", Font.BOLD, 36); Font bIHelvetica = new Font("Helvetica", Font.BOLD + Font.ITALIC, 10);Your choices for the type of font are limited to the list of fonts installed on the user's machine. If you attempt to use a font that is not installed, Java will substitute a default font instead of using your value.
To make use of the font instance of your choice you need to first set the current font. You can then use the drawString() method to draw the string on the applet. The method takes the string and two integers as arguments. The first integer is the x position of the left edge of the string. The second integer is the y position of the bottom of the string to be drawn.
public void init() { resize(300, 100); Font bigBoldCourier = new Font("Courier", Font.BOLD, 36); setFont(bigBoldCourier); } public void paint(Graphics g) { g.drawString("This is big!", 10, 50); }You can also use the drawChars() method to draw text in your applet. This method takes five arguments. The first is an array of characters. The second argument is the position in the array to start and the third argument is how many characters to print from that position forward. The fourth argument is the x position of the left most edge of the line and the fifth argument is the y position of the bottom of the drawn line.
char[] message = {'a','b','c','d','e','f','g','h','i','j'}; public void init() { resize(150, 100); Font bigPlainTimes = new Font("TimesRoman", Font.PLAIN, 24); setFont(bigPlainTimes); } public void paint(Graphics g) { g.drawChars(message, 2, 6, 10, 40); }You can also use a series of methods to retrieve information about the current font attributes being used in your applet.
getName() the string with the type of font by its name getStyle() the integer corresponding to the style getSize() the font size as an integer getFont() returns the current Font object isPlain() true if style is plain isBold() true if style is bold isItalic() true if style is italicTo retrieve information about the dimensions and spacing of the current font object you need to use the Font metrics class. The getFontMetrics method allows you to fill the font metrics object with the correct information that you can then test.
Font bigBoldCourier = new Font("Courier", Font.BOLD, 36); setFont(bigBoldCourier) FontMetrics currentMetrics = getFontMetrics(bigBoldCourier);Testing the font metrics is done with a series of methods defined in the Font metrics class.
getAscent() distance from the base to the top of the characters getDescent() distance from the base to the bottom of the characters getLeading() distance from descent to ascent of next line getHeight() sum of ascent, descent, and leading getWidths() array of widths of the first 256 characters getMaxAdvance() maximum advance width of any character getMaxAscent() maximum ascent of all characters getMaxDescent() maximum descent of all characters stringWidth() width of string in pixels charWidth() width of char in pixels charsWidth() width of an array of characters
Images
Using images in your Java applets is a two step process. You first need to load the image from a file and then you need to draw it to the screen. Fortunately both steps are relatively simple because Java defines standard methods in the Image class that perform these functions exactly.
Java supports the GIF and JPEG file formats. You could always support different file types by coding your own class but this is beyond the scope of this book. It would also be possible to do complex image operations on the given images by using the bitwise operators.
The getImage() method is used for retrieving image files over the network. It can be used in two different ways. The first is to pass it the URL that specifies the location of the file that contains the image you wish to load. This is simple and direct but not as flexible as the second option.
The second option is to call the getImage() method with two arguments. The first argument is the base URL and the second is the path to the image file. This is more flexible because the base URL can be determined at runtime.
getDocumentBase() URL to the directory containing the HTML file getCodeBase() URL to the directory containing the class fileThe two methods will return the same URL if the class file and HTML document are in the same directory. The second argument would then just contain the path from that base URL to the image file.
URL imageLoc = new URL("http://www.a.com/java/applet/images/i1.gif"); Image pict1 = getImage(imageLoc); Image pict1 = getImage(getDocumentBase(), "applet/images/i1.gif"); Image pict1 = getImage(getCodeBase(), "images/i1.gif");These methods would be equivalent if the HTML document was in the java directory and the class file was in the applet directory. If the file is not found getImage() returns a null value.
Determining how to get the URL and paths will affect your applet. If you needed to move the applet or images you would not want to recompile the code with the new information. You should use the tag and read in the path to the image from the HTML. A move would then just mean the need to edit the HTML document rather than recompiling the applet. The two different getImage methods would effect the information you read in. The first would require you to read in the whole URL but the second would only make you read in the path from the base URL.
The end result is that the image will be loaded into your instance of the Image class but nothing else occurs. You need to explicitly draw the image for it to appear in your applet. The two drawImage() methods are similar to the drawString() method you have previously seen. The first takes four arguments consisting of the Image object, the x position of the top left corner in pixels, the y position of the top left corner in pixels, and this. The second version of drawImage() takes six arguments consisting of the Image object, the x position of the top left corner in pixels, the y position of the top left corner in pixels, the width, the height, and this. The last argument serves as an ImageObserver which tracks the progress of the drawImage() method and is also used in the getWidth() and getHeight() methods. The only time you will want to change this argument is if you want to act in certain instances when the image is loading.
public void paint(Graphics g) { g.drawImage(pict1, 10, 10, this); g.drawImage(pict2, 10, 10, 50, 50, this); }The getWidth() and getHeight() methods return the width and height of the image object respectively. These can be used to determine the width and height values to pass to the drawImage() method. If you pass width and height values to the drawImage method that are not the true dimensions, the image will be scaled to fit the dimensions you provide.
import java.applet.*; import java.awt.Graphics; import java.awt.Image; public class JumpinJava extends Applet { Image jumpGif; public void init() { resize(420, 280); jumpGif = getImage(getCodeBase(),"images/JumpinJava.gif"); } public void paint(Graphics g) { int jgwidth = jumpGif.getWidth(this); int jgheight = jumpGif.getHeight(this); g.drawImage(jumpGif, 10, 10, jgwidth, jgheight, this); g.drawImage(jumpGif, 10, 180, jgwidth, jgheight / 3, this); } }The JumpinJava applet loads in a gif file and displays two copies of it in the applet window. The first is the normal size of the image but the second has been compressed vertically by a factor of 3.
The image is drawn slowly as it loads into the applet. You probably noticed the flickering that occurred while the image was being drawn to the screen. This can be minimized using various techniques such as double-buffering or overriding the bahavior of update(). These techniques will be discussed in Chapter 10.
Copying
The copyArea() method allows you to copy a section of the screen and paste it in a new location. It takes six arguments consisting of the x and y position of the top left corner of the area, the width and height of the area, and the x and y distances to move the area.
g.copyArea(10,10,50,100,25,50);
Clearing
The clearRect() method allows you to clear a rectangular section of the screen. It actually fills in the area with the background color. It takes four arguments consisting of the x and y position of the top left corner and the height and width of the region to clear.
g.clearRect(25, 25, 50, 50); int x = this.size().width; int y = this.size().height; g.clearRect(0,0,x,y);The second example clears the entire applet region by retrieving the applet's dimensions and using those in the clearRect method. An equivalent method for clearing would be to set the current color to the background color and draw a filled rectangle.
paint() and repaint()
The paint method is called when the applet is first initialized and any time the window needs to be updated. These events occur whenthe window is moved, brought to the front, updated, or reloaded.
The repaint method allows you to ask Java to repaint the applet's contents at anytime during your applet's life. This enables you to update the screen's contents and create animations, dynamic values, or interactive elements. By calling repaint you are requesting Java to call the paint method.