13.12. (Optional) Case Study: The StillClock Class |
This case study develops a class that displays a clock on a panel. The contract of the class is shown in Figure 13.20.
Let us first write a test program in Listing 13.11 that uses the StillClock class to display an analog clock and uses the MessagePanel class to display the hour , minute, and second in a panel, as shown in Figure 13.21(a).
1 import java.awt.*; 2 import javax.swing.*; 3 4 public class DisplayClock extends JFrame { 5 public DisplayClock() { 6 // Create an analog clock for the current time 7 StillClock clock = new StillClock(); 8 9 // Display hour, minute, and seconds in the message panel 10 MessagePanel messagePanel = new MessagePanel(clock.getHour() + 11 ":" + clock.getMinute() + ":" + clock.getSecond()); 12 messagePanel.setCentered( true ); 13 messagePanel.setForeground(Color.blue); 14 messagePanel.setFont( new Font( "Courier" , Font.BOLD, 16 )); 15 16 // Add the clock and message panel to the frame 17 add(clock); 18 add(messagePanel, BorderLayout.SOUTH); 19 } 20 21 public static void main(String[] args) { 22 DisplayClock frame = new DisplayClock(); 23 frame.setTitle( "DisplayClock" ); 24 frame.setLocationRelativeTo( null ); // Center the frame 25 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 26 frame.setSize( 300 , 350 ); 27 frame.setVisible( true ); 28 } 29 } |
The rest of this section explains how to implement the StillClock class. Since you can use the class without knowing how it is implemented, you can skip the implementation if you wish.
To draw a clock, you need to draw a circle and three hands for second, minute, and hour. To draw a hand, you need to specify the two ends of the line. As shown in Figure 13.21(b), one end is the center of the clock at (xCenter, yCenter) ; the other end, at (xEnd, yEnd) , is determined by the following formula:
xEnd = xCenter + handLength x sin(?) yEnd = yCenter - handLength x cos(?)
Since there are sixty seconds in one minute, the angle for the second hand is
second x (2p/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 sixty minutes in one hour, the angle for the minute hand is
(minute + second/60) x (2p/60)
Since one circle is divided into twelve hours, the angle for the hour hand is
(hour + minute/60 + second/(60 x 60))) x (2p/12)
For simplicity, you can omit the seconds in computing the angles of the minute hand and the hour hand, because they are very small and can be neglected. Therefore, the end-points for the second hand, minute hand, and hour hand can be computed as:
xSecond = xCenter + secondHandLength x sin(second x (2p/60)) ySecond = yCenter - secondHandLength x cos(second x (2p/60)) xMinute = xCenter + minuteHandLength x sin(minute x (2p/60)) yMinute = yCenter - minuteHandLength x cos(minute x (2p/60)) xHour = xCenter + hourHandLength x sin((hour + minute/60) x (2p/60))) yHour = yCenter - hourHandLength x cos((hour + minute/60) x (2p/60)))
The StillClock class is implemented in Listing 13.12.
1 import java.awt.*; 2 import javax.swing.*; 3 import java.util.*; 4 5 public class StillClock extends JPanel { 6 private int hour; 7 private int minute; 8 private int second; 9 10 /** Construct a default clock with the current time */ 11 public StillClock() { 12 setCurrentTime(); 13 } 14 15 /** Construct a clock with specified hour, minute, and second */ 16 public StillClock( int hour, int minute, int second) { 17 this .hour = hour; 18 this .minute = minute; 19 this .second = second; 20 } 21 22 /** Return hour */ 23 public int getHour() { 24 return hour; 25 } 26 27 /** Set a new hour */ 28 public void setHour( int hour) { 29 this .hour = hour; 30 repaint(); 31 } 32 33 /** Return minute */ 34 public int getMinute() { 35 return minute; 36 } 37 38 /** Set a new minute */ 39 public void setMinute( int minute) { 40 this .minute = minute; 41 repaint(); 42 } 43 44 /** Return second */ 45 public int getSecond() { 46 return second; 47 } 48 49 /** Set a new second */ 50 public void setSecond( int second) { 51 this .second = second; 52 repaint(); 53 } 54 55 /** Draw the clock */ 56 protected void paintComponent(Graphics g) { 57 super .paintComponent(g); 58 59 // Initialize clock parameters 60 int clockRadius = 61 ( int )(Math.min(getWidth(), getHeight()) * . 8 * . 5 ); 62 int xCenter = getWidth() / 2 ; 63 int yCenter = getHeight() / 2 ; 64 65 // Draw circle 66 g.setColor(Color.black); 67 g.drawOval(xCenter - clockRadius, yCenter - clockRadius, 68 2 * clockRadius, 2 * clockRadius); 69 g.drawString( "12" , xCenter - 5 , yCenter - clockRadius + 12 ); 70 g.drawString( "9" , xCenter - clockRadius + 3 , yCenter + 5 ); 71 g.drawString( "3" , xCenter + clockRadius - 10 , yCenter + 3 ); 72 g.drawString( "6" , xCenter - 3 , yCenter + clockRadius - 3 ); 73 74 // Draw second hand 75 int sLength = ( int )(clockRadius * . 8 ); 76 int xSecond = ( int )(xCenter + sLength * 77 Math.sin(second * ( 2 * Math.PI / 60 ))); 78 int ySecond = ( int )(yCenter - sLength * 79 Math.cos(second * ( 2 * Math.PI / 60 ))); 80 g.setColor(Color.red); 81 g.drawLine(xCenter, yCenter, xSecond, ySecond); 82 83 // Draw minute hand 84 int mLength = ( int )(clockRadius * . 65 ); 85 int xMinute = ( int )(xCenter + mLength * 86 Math.sin(minute * ( 2 * Math.PI / 60 ))); 87 int yMinute = ( int )(yCenter - mLength * 88 Math.cos(minute * ( 2 * Math.PI / 60 ))); 89 g.setColor(Color.blue); 90 g.drawLine(xCenter, yCenter, xMinute, yMinute); 91 92 // Draw hour hand 93 int hLength = ( int )(clockRadius * . 5 ); 94 int xHour = ( int )(xCenter + hLength * 95 Math.sin((hour % 12 + minute / 60 . ) * ( 2 * Math.PI / 12 ))); 96 int yHour = ( int )(yCenter - hLength * 97 Math.cos((hour % 12 + minute / 60 . ) * ( 2 * Math.PI / 12 ))); 98 g.setColor(Color.green); 99 g.drawLine(xCenter, yCenter, xHour, yHour); 100 } 101 102 public void setCurrentTime() { 103 // Construct a calendar for the current date and time 104 Calendar calendar = new GregorianCalendar(); 105 106 // Set current hour, minute, and second 107 this .hour = calendar.get(Calendar.HOUR_OF_DAY); 108 this .minute = calendar.get(Calendar.MINUTE); 109 this .second = calendar.get(Calendar.SECOND); 110 } 111 112 public Dimension getPreferredSize() { 113 return new Dimension( 200 , 200 ); 114 } 115 } |
The program enables the clock size to adjust as the frame resizes. Every time you resize the frame, the paintComponent method is automatically invoked to paint the new frame. The paintComponent method displays the clock in proportion to the panel width ( getWidth() ) and height ( getHeight() ) (lines 60 “63 in StillClock ).
Note
Like the MessagePanel class, the StillClock class is an example of a reusable class. StillClock will be used throughout the book. StillClock provides many properties and methods that enable it to be used in a wide range of applications. |