Case Study: The ClockPane Class
Tags: java, programming, learning, beginners
Published: 2024-06-20 19:52:22

This case study develops a class that displays a clock on a pane. The contract of the **ClockPane** class is shown in Figure below.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dvlektc6cin1irnmxbaa.png)

Assume **ClockPane** is available; we write a test program in the program below to display an analog clock and use a label to display the hour, minute, and second, as shown in Figure below.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n31mz0bbdkyze5mmsfwe.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hc0vpsedztse6x8qjmcr.png)


The rest of this section explains how to implement the **ClockPane** class. Since you can use the class without knowing how it is implemented, you may skip the implementation if you wish.

To draw a clock, you need to draw a circle and three hands for the second, minute, and hour. To draw a hand, you need to specify the two ends of the line. As shown in Figure 14.42b, one end is the center of the clock at **(centerX, centerY)**; the other end, at **(endX, endY)**, is
determined by the following formula:

`endX = centerX + handLength × sin(θ)
endY = centerY - handLength × cos(θ)`

Since there are 60 seconds in one minute, the angle for the second hand is

`second × (2π/60)`

The position of the minute hand is determined by the minute and second. The exact minute value combined with seconds is **minute + second/60**. For example, if the time is 3 minutes and 30 seconds, the total minutes are 3.5. Since there are 60 minutes in one hour, the angle for the minute hand is

`(minute + second/60) × (2π/60)`

Since one circle is divided into 12 hours, the angle for the hour hand is

`(hour + minute/60 + second/(60 × 60)) × (2π/12)`

For simplicity in computing the angles of the minute hand and hour hand, you can omit the seconds, because they are negligibly small. Therefore, the endpoints for the second hand, minute hand, and hour hand can be computed as:

`secondX = centerX + secondHandLength × sin(second × (2π/60))
secondY = centerY - secondHandLength × cos(second × (2π/60))
minuteX = centerX + minuteHandLength × sin(minute × (2π/60))
minuteY = centerY - minuteHandLength × cos(minute × (2π/60))
hourX = centerX + hourHandLength × sin((hour + minute/60) × (2π/12))
hourY = centerY - hourHandLength × cos((hour + minute/60) × (2π/12))`

The **ClockPane** class is implemented in the program below.

```
package application;
import java.util.Calendar;
import java.util.GregorianCalendar;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.text.Text;

public class ClockPane extends Pane {
	private int hour;
	private int minute;
	private int second;
	
	// Clock pane's width and height
	private double w = 250, h = 250;
	
	/** Construct a default clock with the current time */
	public ClockPane() {
		setCurrentTime();
	}
	
	/** Construct a clock with specified hour, minute, and second */
	public ClockPane(int hour, int minute, int second) {
		this.hour = hour;
		this.minute = minute;
		this.second = second;
		paintClock();
	}
	
	/** Return hour */
	public int getHour() {
		return hour;
	}
	
	/** Set a new hour */
	public void setHour(int hour) {
		this.hour = hour;
		paintClock();
	}
	
	/** return minute */
	public int getMinute() {
		return minute;
	}
	
	/** Set a new minute */
	public void setMinute(int minute) {
		this.minute = minute;
		paintClock();
	}
	
	/** Return second */
	public int getSecond() {
		return second;
	}
	
	/** Set a new second */
	public void setSecond(int second) {
		this.second = second;
		paintClock();
	}
	
	/** Return clock pane's width */
	public double getW() {
		return w;
	}
	
	/** Set clock pane's width */
	public void setW(double w) {
		this.w = w;
		paintClock();
	}
	
	/** Return clock pane's height */
	public double getH() {
		return h;
	}
	
	/** Set clock pane's height */
	public void setH(double h) {
		this.h = h;
		paintClock();
	}
	
	/** Set the current time for the clock */
	public void setCurrentTime() {
		// Construct a calendar for the current date and time
		Calendar calendar = new GregorianCalendar();
		
		// Set current hour, minute and second
		this.hour = calendar.get(Calendar.HOUR_OF_DAY);
		this.minute = calendar.get(Calendar.MINUTE);
		this.second = calendar.get(Calendar.SECOND);
		
		paintClock(); // Repaint the clock
	}
	
	/** Paint the clock */
	protected void paintClock() {
		// Initialize clock parameters
		double clockRadius = Math.min(w, h) * 0.8 * 0.5;
		double centerX = w / 2;
		double centerY = h / 2;
		
		// Draw circle
		Circle circle = new Circle(centerX, centerY, clockRadius);
		circle.setFill(Color.WHITE);
		circle.setStroke(Color.BLACK);
		Text t1 = new Text(centerX - 5, centerY - clockRadius + 12, "12");
		Text t2 = new Text(centerX - clockRadius + 3, centerY + 5, "9");
		Text t3 = new Text(centerX + clockRadius - 10, centerY + 3, "3");
		Text t4 = new Text(centerX - 3, centerY + clockRadius - 3, "6");
		
		// Draw second hand
		double sLength = clockRadius * 0.8;
		double secondX = centerX + sLength * Math.sin(second * (2 * Math.PI / 60));
		double secondY = centerY - sLength * Math.cos(second * (2 * Math.PI / 60));
		Line sLine = new Line(centerX, centerY, secondX, secondY);
		sLine.setStroke(Color.RED);
		
		// Draw minute hand
		double mLength = clockRadius * 0.65;
		double xMinute = centerX + mLength * Math.sin(minute * (2 * Math.PI / 60));
		double minuteY = centerY - mLength * Math.cos(minute * (2 * Math.PI / 60));
		Line mLine = new Line(centerX, centerY, xMinute, minuteY);
		mLine.setStroke(Color.BLUE);
		
		// Draw hour hand
		double hLength = clockRadius * 0.5;
		double hourX = centerX + hLength * Math.sin((hour % 12 + minute / 60.0) * (2 * Math.PI / 12));
		double hourY = centerY - hLength * Math.cos((hour % 12 + minute / 60.0) * (2 * Math.PI / 12));
		Line hLine = new Line(centerX, centerY, hourX, hourY);
		hLine.setStroke(Color.GREEN);
		
		getChildren().clear();
		getChildren().addAll(circle, t1, t2, t3, t4, sLine, mLine, hLine);
	}
}

```


The program displays a clock for the current time using the no-arg constructor (lines 19–21) and displays a clock for the specified hour, minute, and second using the other constructor (lines 24–29). The current hour, minute, and second is obtained by using the **GregorianCalendar** class (lines 87–97). The **GregorianCalendar** class in the Java API enables you to create a **Calendar** instance for the current time using its no-arg constructor. You can then use its methods **get(Calendar.HOUR)**, **get(Calendar.MINUTE)**, and **get(Calendar.SECOND)** to return the hour, minute, and second from a **Calendar** object.

The class defines the properties **hour**, **minute**, and **second** to store the time represented in the clock (lines 11–13) and uses the **w** and **h** properties to represent the width and height of the clock pane (line 16). The initial values of **w** and **h** are set to 250. The **w** and **h** values can be reset using the **setW** and **setH** methods (lines 70, 81). These values are used to draw a clock in the pane in the **paintClock()** method.

The **paintClock()** method paints the clock (lines 100–138). The clock radius is proportional to the width and height of the pane (line 102). A circle for the clock is created at the center of the pane (line 107). The text for showing the hours 12, 3, 6, 9 are created in lines 110–113. The second hand, minute hand, and hour hand are the lines created in lines 115–134. The **paintClock()** method places all these shapes in the pane using the **addAll** method in a list (line 137). Because the **paintClock()** method is invoked whenever a new property (**hour**, **minute**, **second**, **w**, and **h**) is set (lines 28, 39, 50, 61, 72, 83, 96), before adding new contents into the pane, the old contents are cleared from the pane (line 136).