package dt; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.Calendar; import javax.swing.JComponent; @SuppressWarnings("serial") public class Clock implements Runnable { private volatile Thread thread = null; private long lasttime = System.currentTimeMillis(); private boolean stopped = true; private ClockDelegate delegate; private DigitalView view; private int hh, mm, ss; Clock() { Calendar now = Calendar.getInstance(); this.hh = now.get(Calendar.HOUR_OF_DAY); this.mm = now.get(Calendar.MINUTE); this.ss = now.get(Calendar.SECOND); } Clock(int hh, int mm, int ss) { initTime(hh, mm, ss); } public boolean isStopped() { return stopped; } public void setDelegate(ClockDelegate d) { this.delegate = d; } public ClockDelegate getDelegate() { return this.delegate; } public void setTime(int hh, int mm, int ss) { initTime(hh, mm, ss); lasttime = System.currentTimeMillis(); // reset last time internal // clock was changed if (view != null) view.repaint(); } public void resetTime() { Calendar now = Calendar.getInstance(); int hh = now.get(Calendar.HOUR_OF_DAY); int mm = now.get(Calendar.MINUTE); int ss = now.get(Calendar.SECOND); setTime(hh, mm, ss); } public int getHours() { return this.hh; } public int getMinutes() { return this.mm; } public int getSeconds() { return this.ss; } private void initTime(int hh, int mm, int ss) { if (hh < 0) hh = 0; else if (hh > 23) hh = 23; this.hh = hh; if (mm < 0) mm = 0; else if (mm > 59) mm = 59; this.mm = mm; if (ss < 0) ss = 0; else if (ss > 59) ss = 59; this.ss = ss; } private void addTime(int nsecs) { int secs = hh * 3600 + mm * 60 + ss + nsecs; hh = secs / (60 * 60); secs -= hh * (60 * 60); hh %= 24; mm = secs / 60; secs -= mm * 60; ss = secs; } public JComponent createComponent() { view = new DigitalView(); return view; } public void start() { if (stopped) { if (thread == null) { thread = new Thread(this, "Clock"); thread.start(); } stopped = false; } } public void stop() { if (!stopped) { stopped = true; thread = null; } } public void run() { while (this.thread == Thread.currentThread()) { if (view != null) view.repaint(); try { long timenow = System.currentTimeMillis(); int delay = (int) (timenow - lasttime); int nsecs = delay / 1000; int nmillisecs = delay % 1000; addTime(nsecs); lasttime += nsecs * 1000; Thread.sleep(1000 - nmillisecs); } catch (InterruptedException e) { } } } @SuppressWarnings("serial") private class DigitalView extends JComponent { protected Color fg = Color.BLUE, bg = null; protected Font font = new Font("Sans-Serif", Font.BOLD, 36); DigitalView() { FontMetrics fm = getFontMetrics(font); Dimension size = new Dimension(fm.stringWidth("00:00:00"), fm.getHeight()); setPreferredSize(size); setMinimumSize(size); addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { if (stopped) { start(); if (delegate != null) delegate.clockStarted(Clock.this); } else { stop(); if (delegate != null) delegate.clockStopped(Clock.this); } } }); } public void paintComponent(Graphics g) { Dimension size = getSize(); Graphics2D g2d = (Graphics2D) g.create(); g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); java.util.Formatter formatter = new java.util.Formatter(); String s = formatter.format("%02d:%02d:%02d", hh, mm, ss).toString(); g2d.setFont(font); FontMetrics fm = g2d.getFontMetrics(); int x = (size.width - fm.stringWidth(s)) / 2; int y = (size.height - fm.getHeight()) / 2 + fm.getAscent(); if (bg != null) { g2d.setColor(bg); g2d.fillRect(0, 0, size.width, size.height); } g2d.setColor(fg); g2d.drawString(s, x, y); } } }