アナログ時計。テストプログラム


アナログ時計です。
テストプログラムということでコンパクトにまとめようと心掛けました。


AnalogClockTest.jar


おまけで縦横に引き伸ばすとちゃんと画像再計算したりとかもやってます。


ウィンドウサイズを縦長にしてみたり。


横長にしたりとか。


因みにタイマー、タイマータスククラスは使わずスレッドクラスとランナブルインターフェイスで、
毎秒のアップデートを行ってます。
何故かと言うと内蔵時計の時間が過去に遡るとその時点でタイマータスクが止まってしまうからです。


例えば Windows だと、 OS 内蔵の NTP クライアントから時刻更新が行われた時など、
内蔵時計が少しでも進んでると時間補正で過去に戻されてしまい、その時点でスレッドが止まってしまいます。
一見便利に見えたけど、実は脆弱なクラスだったという。
利用を考えてる方は、上記注意点を考慮した上で導入を検証したほうが良いかと。


AnalogClockTest.java

/**
* 
* AnalogClockTest
* 
* @author DumBo
* @version 0.01 (Jun 22, 2012)
* 
*/


import java.util.*;
import java.awt.*;
import java.awt.event.*;

class AnalogClockTest extends Frame implements Runnable {
	
	// 等分数
	/* 円周の角度を求めるための等分数で、一周を12時間とした割合て扱うことを示します。 */
	static final double HOUR_DIVIDED_EQUALLY        = 12.0d;
	
	/* 円周の角度を求めるための等分数で、一周を60分とした割合で扱うことを示します。 */
	static final double MINUTE_DIVIDED_EQUALLY      = 60.0d;
	
	/* 円周の角度を求めるための等分数で、一周を60秒とした割合で扱うことを示します。 */
	static final double SECOND_DIVIDED_EQUALLY      = 60.0d;
	
	/* 円周の角度を求めるための等分数で、一周を1000ミリ秒とした割合で扱うことを示します。 */
	static final double MILLISECOND_DIVIDED_EQUALLY = 1000.0d;
	
	public static void main(String[] args) {
		new AnalogClockTest();
	}
	
	public AnalogClockTest() {
		
		this.setTitle("AnalogClockTest");
		this.setSize(300, 300);
		this.setLocationRelativeTo(null);
		this.setResizable(true);
		this.setVisible(true);
		
		addWindowListener(
			new WindowAdapter() {
				public void windowClosing(WindowEvent w) {
					System.exit(0);
				}
			}
		);
		
		Thread thread = new Thread(this);
		thread.start();
		
	}
	
	@Override
	public void run() {
		while(true) {
			try {
				Thread.sleep(1000);
			} catch(InterruptedException e) {
				e.printStackTrace();
			}
			repaint();
		}
	}
	
	public void paint(Graphics g) {
		
		// 盤面の描画
		int centerX = (int)(getWidth()  * 0.5d);
		int centerY = (int)(getHeight() * 0.5d);
		g.drawOval(0, 0, getWidth(), getHeight());
		
		// 現在の時間を取得
		Calendar calendar = Calendar.getInstance();
		
		double angle;
		int pointX;
		int pointY;
		
		// 短針(時)の描画
		angle = getAngleHour(calendar.get(Calendar.HOUR), 
			calendar.get(Calendar.MINUTE));
		pointX = (int)(centerX + getWidth()  * 0.45d * 0.7d * Math.sin(angle));
		pointY = (int)(centerY - getHeight() * 0.45d * 0.7d * Math.cos(angle));
		g.drawLine(pointX, pointY, centerX, centerY);
		
		// 長針(分)の描画
		angle = getAngleMinute(calendar.get(Calendar.MINUTE), 
			calendar.get(Calendar.SECOND));
		pointX = (int)(centerX + getWidth()  * 0.45d * 0.8d * Math.sin(angle));
		pointY = (int)(centerY - getHeight() * 0.45d * 0.8d * Math.cos(angle));
		g.drawLine(pointX, pointY, centerX, centerY);
		
		// 秒針の描画
		angle = getAngleSecond(calendar.get(Calendar.SECOND), 
			calendar.get(Calendar.MILLISECOND));
		pointX = (int)(centerX + getWidth()  * 0.45d * 0.9d * Math.sin(angle));
		pointY = (int)(centerY - getHeight() * 0.45d * 0.9d * Math.cos(angle));
		g.drawLine(pointX, pointY, centerX, centerY);
		
	}
	
	/** 
	* 
	* 時計盤面を一周とした、短針(時)の角度を返します。
	* 
	* @param hour 指定された現在の時間
	* @param minute 指定された現在の分
	* 
	* @return 指定された現在の短針の角度(ラジアン値)
	* 
	*/
	public double getAngleHour(int hour, int minute) {
		return getAngleCircumference(HOUR_DIVIDED_EQUALLY, 
			hour + minute / MINUTE_DIVIDED_EQUALLY);
	}
	
	/** 
	* 
	* 時計盤面を一周とした、長針(分)の角度を返します。
	* 
	* @param minute 指定された現在の分
	* @param second 指定された現在の秒
	* 
	* @return 指定された現在の長針の角度(ラジアン値)
	* 
	*/
	public double getAngleMinute(int minute, int second) {
		return getAngleCircumference(MINUTE_DIVIDED_EQUALLY, 
			minute + second / SECOND_DIVIDED_EQUALLY);
	}
	
	/** 
	* 
	* 時計盤面を一周とした、秒針の角度を返します。
	* 
	* @param second 指定された現在の秒
	* @param millisecond 指定された現在のミリ秒
	* 
	* @return 指定された現在の秒針の角度(ラジアン値)
	* 
	*/
	public double getAngleSecond(int second, int millisecond) {
		return getAngleCircumference(SECOND_DIVIDED_EQUALLY, 
			second + millisecond / MILLISECOND_DIVIDED_EQUALLY);
	}
	
	/*
	* 
	* 時計盤面の円周を、指定された等分数を一周における割合として扱い、指定された数の角度を返します。
	* 
	* @param numberDividedEqually 指定された等分数
	* @param number 指定された数
	* 
	* @return 指定された数の角度(ラジアン値)
	* 
	*/
	private double getAngleCircumference(double numberDividedEqually, double number) {
		// 現在の角度t=(一周の角度(2π≒2×円周率))÷等分数×角度を求めたい数
		return 2.0d * Math.PI / numberDividedEqually * number;
	}
	
}