// ClockPanel.java -- Manages the appearance of the clock, and keeps track of // the current time, and periodically checks to see if the alarm time has been // reached. This is not a robust implementation. For example, by default the // current time and alarm time are set to 12:00:00. import javax.swing.*; // for JPanel import java.awt.*; // for graphics import java.awt.geom.*; // for ellipse import java.awt.event.*; // for action listener public class ClockPanel extends JPanel { private static final int SIZE = 600; private static final int BORDER = 20; private static final int RADIUS = SIZE / 2 - BORDER; private static final int CENTER = SIZE / 2; private Ellipse2D.Double circle; private Line2D.Double [] hourMark; private Line2D.Double hourHand; private Line2D.Double minuteHand; private Line2D.Double secondHand; private int hour; private int minute; private int second; private long currentSecond; private int alarmHour; private int alarmMinute; private int alarmSecond; public ClockPanel() { // need inner class for listener, and attach listener // The following code is based on advice from the API under "Timer". int delay = 1000; ActionListener taskPerformer = new ActionListener() { public void actionPerformed(ActionEvent evt) { currentSecond = System.currentTimeMillis() / 1000; repaint(); } }; new Timer(delay, taskPerformer).start(); // set attributes setPreferredSize(new Dimension(SIZE, SIZE)); circle = new Ellipse2D.Double(BORDER, BORDER, 2*RADIUS, 2*RADIUS); hourMark = new Line2D.Double[12]; for (int i = 0; i < 12; ++i) { // Each hour, the angle changes by 30 degrees, or PI/6. // Because pixel number increase downward, we need -sin. double x1 = CENTER + (CENTER-BORDER) * Math.cos(Math.PI/2 - Math.PI/6*i); double y1 = CENTER + (CENTER-BORDER) * -Math.sin(Math.PI/2 - Math.PI/6*i); double x2 = CENTER + (CENTER-2*BORDER) * Math.cos(Math.PI/2 - Math.PI/6*i); double y2 = CENTER + (CENTER-2*BORDER) * -Math.sin(Math.PI/2 - Math.PI/6*i); hourMark[i] = new Line2D.Double(x1, y1, x2, y2); } } // Draw the clock every second. public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; // now draw geometric shapes with g2.draw(---) g2.draw(circle); for (int i = 0; i < 12; ++i) g2.draw(hourMark[i]); // The code that updates the clock needs to be here because we want to // repaint every second. The constructor only gets called once at the // beginning of the application. // Find out what time it really is to set hour, minute and second. // Note that the system time is always given in GMT. currentSecond = System.currentTimeMillis() / 1000; currentSecond -= 5 * 60 * 60; hour = (int) (currentSecond % (12 * 60 * 60) / (60 * 60)); minute = (int) (currentSecond % (60 * 60) / 60); second = (int) (currentSecond % 60); // Each second, the angle changes by 6 degrees, or PI/30. double x1 = CENTER; double y1 = CENTER; double x2 = CENTER + (CENTER-3*BORDER) * Math.cos(Math.PI/2 - Math.PI/30*second); double y2 = CENTER + (CENTER-3*BORDER) * -Math.sin(Math.PI/2 - Math.PI/30*second); secondHand = new Line2D.Double(x1, y1, x2, y2); // Now we need to continue with the minute hand and hour hand.... double minuteAngle = Math.PI/2 - Math.PI/30*(minute + second/60.0); double hourAngle = Math.PI/2 - Math.PI/6*(hour + minute/60.0 + second/3600.0); x2 = CENTER + (CENTER - 6*BORDER) * Math.cos(minuteAngle); y2 = CENTER + (CENTER - 6*BORDER) * -Math.sin(minuteAngle); minuteHand = new Line2D.Double(x1, y1, x2, y2); x2 = CENTER + (CENTER - 8*BORDER) * Math.cos(hourAngle); y2 = CENTER + (CENTER - 8*BORDER) * -Math.sin(hourAngle); hourHand = new Line2D.Double(x1, y1, x2, y2); g2.draw(secondHand); g2.draw(minuteHand); g2.draw(hourHand); // Now, check to see if it's time to wake up! // Call the 'simple midi player' I found on the Web. if (hour == alarmHour && minute == alarmMinute && second == alarmSecond) { new VerySimpleMidiPlayer(); } } // This function is called from the button listener in the InputPanel class. public void setAlarmTime(int h, int m, int s) { alarmHour = h; alarmMinute = m; alarmSecond = s; } }