// Copyright 1997-2015 Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland // www.source-code.biz, www.inventec.ch/chdh // // This module is multi-licensed and may be used under the terms of any of the following licenses: // // LGPL, GNU Lesser General Public License, V2.1 or later, http://www.gnu.org/licenses/lgpl.html // EPL, Eclipse Public License, V1.0 or later, http://www.eclipse.org/legal // // Please contact the author if you need another license. // This module is provided "as is", without warranties of any kind. // // Home page: http://www.source-code.biz/snippets/java/1.htm import java.awt.Color; import java.awt.Graphics; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Image; import java.awt.image.ImageProducer; import java.awt.image.FilteredImageSource; import java.applet.Applet; import java.util.GregorianCalendar; /** * A station clock applet, drawn with anti-aliased graphics. * This applet uses the AntiAliasingFilter class to draw a clock. */ public class ClockApplet extends Applet implements Runnable { private String clockLabel = "source-code.biz"; private Color bgColor; private int aaScalingFactor; // the anti-aliasing scaling factor private Color secPtrColor = new Color(0xCC, 0x00, 0x00); private Color borderColor = new Color(0xC0, 0xC0, 0xC0); private Thread thread; private Image staticImg; private Image dynImg; private int r; private int centerX; private int centerY; private void drawRadial (Graphics g, double alpha, int r1, int r2, int width1, int width2) { double sin = Math.sin(alpha); double cos = Math.cos(alpha); double pm1X = sin * r1; double pm1Y = cos * r1; double pm2X = sin * r2; double pm2Y = cos * r2; double pxr[] = new double[4]; double pyr[] = new double[4]; pxr[0] = pm1X - cos * width1 / 2; pyr[0] = pm1Y + sin * width1 / 2; pxr[3] = pm1X + cos * width1 / 2; pyr[3] = pm1Y - sin * width1 / 2; pxr[1] = pm2X - cos * width2 / 2; pyr[1] = pm2Y + sin * width2 / 2; pxr[2] = pm2X + cos * width2 / 2; pyr[2] = pm2Y - sin * width2 / 2; int pxi[] = new int[4]; int pyi[] = new int[4]; for (int i = 0; i < 4; i++) { pxi[i] = centerX + (int)Math.round(pxr[i]); pyi[i] = centerY - (int)Math.round(pyr[i]); } g.fillPolygon(pxi, pyi, 4); } private void drawRadialFilledCircle (Graphics g, double alpha, int r1, int circR) { int p0X = (int)Math.round( centerX + Math.sin(alpha) * r1 ); int p0Y = (int)Math.round( centerY - Math.cos(alpha) * r1 ); g.fillOval(p0X - circR, p0Y - circR, 2 * circR, 2 * circR); } private void drawClockLabel (Graphics g) { g.setColor(borderColor); int fontSize = r * 20 / 200; Font f = new Font("Helvetica", Font.PLAIN, fontSize); g.setFont(f); FontMetrics fm = g.getFontMetrics(); g.drawString(clockLabel, centerX - fm.stringWidth(clockLabel) / 2, centerY + r / 2); } private void drawFilledCircle (Graphics g, int r, Color c) { g.setColor(c); g.fillOval(centerX - r, centerY - r, 2 * r, 2 * r); } private void drawStaticImage (Graphics g, int width, int height) { r = Math.min(width, height) * 7 / 16; centerX = width / 2; centerY = height / 2; g.setColor(bgColor); g.fillRect(0, 0, width, height); int borderWidth = r / 54; // drawFilledCircle(g, r + borderWidth + borderWidth, new Color(0xf0, 0xf0, 0xf0)); drawFilledCircle(g, r + borderWidth, borderColor); drawFilledCircle(g, r, Color.white); g.setColor(Color.black); for (int i = 0; i < 60; i++) { boolean big = i % 5 == 0; int rlength = big ? r * 10 / 44 : r * 3 / 44; rlength = Math.max(1, rlength); int rwidth = big ? r * 3 / 44 : r / 44; rwidth = Math.max(1, rwidth); int r2 = r * 42 / 44; drawRadial(g, 2 * Math.PI / 60 * i, r2 - rlength, r2, rwidth, rwidth); } drawClockLabel(g); } private void generateStaticImage (int width, int height) { staticImg = createImage(width, height); Graphics g = staticImg.getGraphics(); drawStaticImage(g, width, height); g.dispose(); } private void drawDynamicImage (Graphics g, int hour, int min, int sec) { g.setColor(Color.black); drawRadial(g, 2 * Math.PI * ( (hour % 12) * 60 + min) / (12 * 60), -r * 10 / 44, r * 27 / 44, r * 5 / 44, r * 4 / 44); drawRadial(g, 2 * Math.PI * min / 60, -r * 10 / 44, r * 40 / 44, r * 9 / 88, r * 3 / 44); g.setColor(secPtrColor); int r_1_44 = Math.max(1, r * 1 / 44); drawRadial(g, 2 * Math.PI * sec / 60, -r * 14 / 44, r * 27 / 44, r_1_44, r_1_44); drawRadialFilledCircle(g, 2 * Math.PI / 60 * sec, r * 27 / 44, r * 9 / 88); } private Image genImg (int width, int height, int hour, int min, int sec) { int aaWidth = width * aaScalingFactor; int aaHeight = height * aaScalingFactor; if (staticImg == null || staticImg.getWidth(null)!=aaWidth || staticImg.getHeight(null)!=aaHeight) { generateStaticImage(aaWidth, aaHeight); dynImg = createImage(aaWidth, aaHeight); } Graphics g = dynImg.getGraphics(); g.drawImage(staticImg, 0, 0, null); drawDynamicImage(g, hour, min, sec); g.dispose(); if (aaScalingFactor <= 1) { return dynImg; } // AreaAveragingScaleFilter aaFilter = new AreaAveragingScaleFilter(width, height); // ReplicateScaleFilter aaFilter = new ReplicateScaleFilter(width, height); AntiAliasingFilter aaFilter = new AntiAliasingFilter(aaScalingFactor); ImageProducer aaProd = new FilteredImageSource(dynImg.getSource(), aaFilter); Image outImg = createImage(aaProd); return outImg; } private void getTimeNew (int[] time) { GregorianCalendar cal = new GregorianCalendar(); time[0] = cal.get(GregorianCalendar.HOUR_OF_DAY); time[1] = cal.get(GregorianCalendar.MINUTE); time[2] = cal.get(GregorianCalendar.SECOND); } public void paint (Graphics g) { int time[] = new int[3]; getTimeNew(time); Image img = genImg(getSize().width, getSize().height, time[0], time[1], time[2]); g.drawImage(img, 0, 0, null); } public void update (Graphics g) { paint(g); } public void run() { while (true) { int secOffs = (int)(System.currentTimeMillis() % 1000); int delayT = 1000 - secOffs; try { Thread.sleep(delayT); } catch (Exception e) { throw new RuntimeException(e.getMessage()); } if (thread != Thread.currentThread()) { break; } repaint(); }} public void start() { if (thread == null) { thread = new Thread(this); thread.start(); }} public void stop() { thread = null; } public String getAppletInfo() { return "ClockApplet version 2015-02-07 by Christian d'Heureuse (www.source-code.biz)"; } public void setBgColor (String s) { try { bgColor = new Color(Integer.parseInt(s, 16)); } catch (Exception e) { throw new IllegalArgumentException("Invalid bgColor parameter.", e); } repaint(); } public void setAaScalingFactor (String s) { try { aaScalingFactor = Integer.parseInt(s); } catch (Exception e) { throw new IllegalArgumentException("Invalid aaScalingFactor parameter.", e); } repaint(); } private void getParms() { bgColor = Color.white; String s = getParameter("bgColor"); if (s != null) { setBgColor(s); } aaScalingFactor = 1; s = getParameter("aaScalingFactor"); if (s != null) { setAaScalingFactor(s); }} public void init() { getParms(); setBackground(bgColor); } }