//------------------------------ IMPORTS ------------------------------- import java.util.Date; import java.applet.*; import java.awt.*; import java.awt.event.*; //========================== TickTock CLASS ============================ /** * This applet is quite simple, since all thr real work goes on * in the Timer object. Besides the timer, the applet just contains * four buttons, for toggling between time and alarm mode, setting * the hour and minute, and turning off the alarm. */ public class TickTock extends Applet implements ActionListener { private Timer timeDisplay; // the clock private Button bMode, // toggle the mode bHr, // increment the alarm hour bMin, // increment the alarm minute bOff; // turn off the alarm /** * Lay out the timer and the buttons, and register * the buttons as sources of action events. */ public void init() { setLayout(new BorderLayout()); Panel p = new Panel(); bMode = new Button("Alarm"); bHr = new Button("Hour+"); bMin = new Button("Min+"); bOff = new Button("OFF"); p.add(bMode); p.add(bHr); p.add(bMin); p.add(bOff); add("South", p); bHr.setEnabled(false); bMin.setEnabled(false); bOff.setEnabled(false); timeDisplay = new Timer(); add("Center", timeDisplay); bMode.addActionListener(this); bHr.addActionListener(this); bMin.addActionListener(this); bOff.addActionListener(this); } /** * Called each time the browser returns to the page containing * this applet. In this program, we just start the timer. */ public void start() { timeDisplay.start(); } /** * Called when the browser leaves the page containing this * applet. In this program, we just stop the timer, so * that its thread doesn't keep running (at the expense * of other threads) when the timer isn't visible. */ public void stop() { timeDisplay.stop(); } /** * Respond to a click on one of the four control buttons. */ public void actionPerformed(ActionEvent e) { Object source = e.getSource(); if (source == bMode) // The user has changed from time to alarm mode or // vice versa. { if (bMode.getLabel().equals("Alarm")) // Get things ready for the user to set the alarm. { bMode.setLabel(" Set "); bHr.setEnabled(true); bMin.setEnabled(true); timeDisplay.setTimeMode(false); } else // Set the alarm to the time the user set // and then return to clock mode. { // Tell the timer to set its alarm, timeDisplay.setAlarm(true); // and reset our widgets back to time mode. bMode.setLabel("Alarm"); bHr.setEnabled(false); bMin.setEnabled(false); bOff.setEnabled(true); timeDisplay.setTimeMode(true); } } else if (source == bHr) // Increment the hour part of the display. { timeDisplay.incrementAlarmHour(); } else if (source == bMin) // Increment the minute part of the display. { timeDisplay.incrementAlarmMinute(); } else if (source == bOff) // Tell the timer to turn its alarm off. { timeDisplay.setAlarm(false); bOff.setEnabled(false); } } } //============================ Timer CLASS ============================= /** * A Timer object displays the current system time in hh:mm:ss * format, followed by "A.M." or "P.M.," as appropriate. * A Timer has an alarm that can be set by the user. * This class carries its own thread for updating the time. */ class Timer extends Canvas implements Runnable { private Thread clockThread; // the thread private int hour = 0, // displayed hour minute = 0, // displayed minutes second = 0, // displayed seconds aHour = 0, // alarm hour aMinute = 0; // alarm minutes private boolean alarmSet = false, timeMode = true; /** * All we do to construct a Timer is set its background color * and flag the clockThread as null. */ public Timer() { setBackground(Color.black); clockThread = null; } //------------------------- Thread Methods ------------------------- /** * Called to start the clock. We make a new clock thread, * if needed, and start it. */ public void start() { if (clockThread == null) { clockThread = new Thread(this); clockThread.start(); } } /** * Called to stop the clock. We check that the thread * exists, and if it does, we kill it. */ public void stop() { if (clockThread != null) { clockThread.stop(); clockThread = null; } } /** * This is the implementation we promised when we declared this * class to be Runnable. This is where the clockThread * executes. */ public void run() { while (clockThread != null) { if (timeMode) // We're in time mode, so just update the timer. { Date now = new Date(); updateTime(now.getHours(), now.getMinutes(), now.getSeconds()); } else // We're in alarm-setting mode now, so ask the timer // to show its alarm setting, for possible changes // by the user. { updateTime(aHour, aMinute, 0); } try // clockThread politely sleeps here, so that other // threads have a chance do do their things (like // painting and responding to button clicks). { Thread.sleep(250); } catch (InterruptedException e) { } } } //------------------------- Display Methods ------------------------ /** * Repaint the display, making sure everything is formatted * as it should be and is drawn in the right color. */ public void paint(Graphics g) { String minSep = ":"; // separator for hh:mm String secSep = ":"; // separator for mm:ss String ampm = " "; // "A.M." or "P.M." int adjHour = hour; // conversion from 24-hour format. // Make the String for A.M./P.M. if ((hour >= 0) && (hour < 12)) { ampm = ampm + "A.M."; } else { ampm = ampm + "P.M."; } // Set the hour displayed to reflect a 12-hour clock. if (hour > 12) { adjHour = hour - 12; } if (hour == 0) { adjHour = 12; } // Insert leading zeros into the time, if necessary if (minute < 10) { minSep = minSep + "0"; } if (second < 10) { secSep = secSep + "0"; } // Set the horizontal offset to compensate for a // one- or two digit hour. int offset; if (adjHour >= 10) { offset = 10; } else { offset = 30; } // Finally, draw the time string in the // appropriate color. if (alarmTriggered()) { g.setColor(Color.red); } else { g.setColor(Color.green); } g.setFont(new Font("Helvetica",Font.BOLD,36)); g.drawString(adjHour + minSep + minute + secSep + second, offset, 50); g.setFont(new Font("Helvetica", Font.BOLD, 24)); g.drawString(ampm, 155, 50); } /** * Set the time shown to h hours, m minutes, s seconds. * We only repaint if the time has changed. Doing so, we * eliminate most of the annoying flicker that comes from * frequent calls to repaint(). In the next chapter, * you'll learn how to eliminate the flicker entirely. * CALLED BY: run() */ private void updateTime(int h, int m, int s) { if ((s != second) || (m != minute) || (h != hour)) { hour = h; minute = m; second = s; repaint(); } } //-------------------------- Alarm Methods ------------------------- /** * Set the time mode to time (if the argument is true) * or alarm (if the argument is false). */ public void setTimeMode(boolean timeMode) { this.timeMode = timeMode; } /** * If the argument is true, enable the alarm. If the * argument is false, disable the alarm. */ public void setAlarm(boolean isOn) { alarmSet = isOn; } /** * Increase the alarm hour setting by 1, making sure * that 0 <= aHour < 24. */ public void incrementAlarmHour() { aHour++; if (aHour == 24) { aHour = 0; } updateTime(aHour, aMinute, 0); } /** * Increase the alarm minute setting by 1, making sure * that 0 <= aMinute < 60. */ public void incrementAlarmMinute() { aMinute++; if (aMinute == 60) { aMinute = 0; } updateTime(aHour, aMinute, 0); } /** * Detect whether the alarm should go off (i.e., alarm has been * set and the current time is later than the alarm setting) * and return the appropriate value. * CALLED BY: paint(). */ private boolean alarmTriggered() { return alarmSet && ((hour > aHour) || ((hour == aHour) && (minute >= aMinute))); } }