Step 6: The Clock Hands

We'll finish ClockApplet in this step by completing the drawFace() method. Before we do that, let's take a look at the new drawHand() method, which draws a single hour or minute hand. Add the following after drawFace():

// Draw a minute or hour hand
private void drawHand(Graphics g, double tick, int length, Color color) {
	Point points[] = {
		getArcPoint(tick, length),
		getArcPoint(tick - 5, length / 5),
		getArcPoint(tick, -length / 8),
		getArcPoint(tick + 5, length / 5),
		getArcPoint(tick, length)
	};

	// Create the polygon
	Polygon poly = new Polygon(), shadow = new Polygon(), 
		light = new Polygon(), dark = new Polygon();

	for(int i = 0; i < points.length; i++) {
		poly.addPoint(points[i].x, points[i].y);
		shadow.addPoint(points[i].x + 3, points[i].y + 3);
		light.addPoint(points[i].x - 1, points[i].y - 1);
		dark.addPoint(points[i].x + 1, points[i].y + 1);
	}

	g.setColor(backColor.darker());
	g.fillPolygon(shadow);

	g.setColor(color.brighter());
	g.fillPolygon(light);
	g.setColor(color.darker());
	g.fillPolygon(dark);
	g.setColor(color);
	g.fillPolygon(poly);
}

drawHand in Detail

The drawHand() method takes four arguments: a Graphics object g on which to draw, the tick mark the hand is pointing at, the length of the hand, and the color to draw it in.

Inside the procedure, we first define an array of points called, appropriately enough, points:

Point points[] = {
	getArcPoint(tick, length),
	getArcPoint(tick - 5, length / 5),
	getArcPoint(tick, -length / 8),
	getArcPoint(tick + 5, length / 5),
	getArcPoint(tick, length)
};

An array is collection of like objects that can be indexed. The two brackets [] after an identifier indicate that the variable is an array. Here is the syntax for creating an array:

data-type identifier[] = { item1, item2, ... }

You access the elements in an array like this: identifier[index]. Indexing starts at 0, so you would get the first item by identifier[0], the second by identifier[1], etc.

A clock hand is shaped like an elongated diamond. In the declaration of points above, we define an array of Point objects and fill it with five points that define the vertices of that diamond. (The last point is the same as the first to close the polygon.) These are calculated by calling getArcPoint().

After that, we define four Polygon objects called poly (the main polygon), shadow (its dark gray shadow), light (the 3D lighted edge), and dark (the 3D shadowed edge). A Polygon object holds a collection of vertices. We now fill the polygons with vertices in the subsequent for loop:

for(int i = 0; i < points.length; i++) {
	poly.addPoint(points[i].x, points[i].y);
	shadow.addPoint(points[i].x + 3, points[i].y + 3);
	light.addPoint(points[i].x - 1, points[i].y - 1);
	dark.addPoint(points[i].x + 1, points[i].y + 1);
}

This simply iterates through each Point object in the points array and adds the vertex to each polygon with the addPoint() method, offsetting its coordinates by a little to create a 3D effect. The length field of an array holds the number of objects in that array:

points.length

Now comes the drawing part. We set the drawing color to a darker version of backColor by calling the darker() method. Then we draw the polygon by calling fillPolygon(shadow). Next, we draw the lighted edge (using the brighter() method to brighten the color), the shadowed edge, and finally the polygon itself.

Drawing the Clock Face

After you've digested all that, let's move on to the drawFace() method. Add the statements in blue:

// Draw all clock hands
private void drawFace() {
	Graphics g = faceBuffer.getGraphics();
	g.drawImage(tickImage, 0, 0, null);

	int h = now.getHours(), m = now.getMinutes(), s = now.getSeconds();
	drawHand(g, (h % 12) * 5 + m / 12.0, hourHSize, hrHColor);
	drawHand(g, m + s / 60.0, minHSize, minHColor);

	// Draw the second hand
	Point p = getArcPoint(s, secHSize);
	g.setColor(secHColor);
	g.drawLine(halfSize, halfSize, p.x, p.y);
}

We call the getHours(), getMinutes(), and getSeconds() methods of the now object (which is a Date) to get the current hour, minute, and second, assigning them to integers called h, m, and s, respectively. Then we call our drawHand() method twice with all the appropriate parameters to draw the hour and minute hand. (You can figure out the math, if you want!)

Finally, we draw the second hand. With a call to getArcPoint() to get the position of the hand's tip, a call to setColor() to set the drawing color, and a call to drawLine() to draw a line from the center to that tip, we're done with ClockApplet!

In the complete listing of ClockApplet, you'll also find the two documentation functions, getAppletInfo() and getParameterInfo().

Our next applet is...a scrolling text marquee!


1