Gobble up pudding

プログラミングの記事がメインのブログです。

MENU

シンプルアナログ時計 Part2

スポンサードリンク


JavaのSwingを使った簡単なシンプルなアナログ時計です!
ここではThreadを使っていますがTimerでもいけますね。
スレッドって本当に必要なときでない限り
Javaソースを参考にしたページがあってここにリンクを貼りたいのですが、
いまとなっては見つからず……。
アナログ時計のサンプルも最近けっこうごろごろ転がっていて
なかなかカスタマイズ性の高そうなものもあるんで
検索して調べてみると面白いかもしれません。

ソースコード

package purin;

import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.util.Calendar;
import java.util.GregorianCalendar;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Clock01 extends JFrame implements Runnable {

    private static final long serialVersionUID = 1L;
    Container  con;
    Thread th;
    static final int sizBase = 200;
    static final int sizX = sizBase + 10;
    static final int sizY = sizBase + 40;

    public Clock01() {
        setTitle("とけい");
        setSize(sizX,sizY);
        con = getContentPane();
        ClockPanel cp = new ClockPanel();
        con.add(cp, "Center");
        clockStart();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public void clockStart() {
        if ( th == null ) {
            th = new Thread(this);
            th.start();
        }
        else th = null;
    }

    public void run() {
        Thread cth = Thread.currentThread();
        while ( th == cth ) {
            repaint();
            try {
                Thread.sleep(1000);
            } catch(InterruptedException e) {
            }
        }
        repaint();
    }

    public static void main(String[] args) {
        Clock01 ck01 = new Clock01();
        ck01.setVisible(true);
    }
}

class  ClockPanel extends JPanel {

    private static final long serialVersionUID = 1L;
    static final double PI = 3.1416;
    static final double DegrOf0h    = PI / 2.0;  // 0時の角度(ラジアン)
    static final double DegrOf1h    = PI / 3.0;  // 1時の角度(ラジアン)
    static final double DegrPerHour = PI / 6.0;  // 1時間あたりの角度(ラジアン)
    static final double DegrPerMin  = PI / 30.0; // 1分あたりの角度(ラジアン)
    static final double DegrPerSec  = PI / 30.0; // 1秒あたりの角度(ラジアン)
    static final int    ClockBaseSize = 180;     // 時計基準サイズ
    static final int    RadiusOfFont = ClockBaseSize / 2 - 15; // フォントの半径
    static final int    SecHandLen  = 80;
    static final int    MinHandLen  = 70;
    static final int    HourHandLen = 60;
    double  s,m,h;
    int  centerX, centerY;
    double  sAng,mAng,hAng;
    Font ft;
    private class Point { // InnerClass 無理やり構造体…こんな使い方いいの?
        int[] px;
        int[] py;
        Point() {
            px = new int[4];
            py = new int[4];
        }
    }

    public ClockPanel() {
        ft = new Font("SansSerif",Font.BOLD,24);
        centerX = 100;
        centerY = 100;
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setFont(ft);
        g.setColor(Color.white);
        g.fillOval(10,10,180,180);
        g.setColor(Color.black);
        double theta = DegrOf1h;
        FontMetrics  fm = g.getFontMetrics(ft);
        int numH = fm.getHeight()/2;
        for ( int i=1; i<=12; i++ ) {
            String  num = Integer.toString(i);
            int x = centerX + (int)(Math.cos(theta) * RadiusOfFont);
            int y = centerY - (int)(Math.sin(theta) * RadiusOfFont);
            int numW = fm.stringWidth(num);
            g.drawString(num, x - numW / 2, y + numH / 2);
            theta = theta - DegrPerHour;
        }
        GregorianCalendar cal = new GregorianCalendar();
        s = (double)(cal.get(Calendar.SECOND));
        m = (double)(cal.get(Calendar.MINUTE)) + s / 60.0;
        h = (double)(cal.get(Calendar.HOUR))   + m / 60.0;

        // 針の位置を示す角度の計算
        sAng = DegrOf0h - DegrPerSec  * s;
        mAng = DegrOf0h - DegrPerMin  * m;
        hAng = DegrOf0h - DegrPerHour * h;

        Point[] pt = new Point[3];
        pt[0] = createClockHand(SecHandLen,  centerX, centerY, sAng, PI / 24.0);
        pt[1] = createClockHand(MinHandLen,  centerX, centerY, mAng, PI / 20.0);
        pt[2] = createClockHand(HourHandLen, centerX, centerY, hAng, PI / 16.0);

        // 秒・分・時針を描く
        g.setColor(Color.magenta);
        g.fillPolygon(pt[0].px, pt[0].py, 4);
        g.setColor(Color.blue);
        g.fillPolygon(pt[1].px, pt[1].py, 4);
        g.fillPolygon(pt[2].px, pt[2].py, 4);
    }

    private Point createClockHand(int typeLen, int centerX, int centerY,
            double angle1, double angle2 ) {
        final int Len = 20;
        Point pt = new Point();
        // 中心のx,y座標
        pt.px[0] = centerX;
        pt.py[0] = centerY;
        // 時計の中心と針の先端以外の二つの頂点の座標(右)
        pt.px[1] = centerX + (int)(Len * Math.cos(angle1 + angle2));
        pt.py[1] = centerY - (int)(Len * Math.sin(angle1 + angle2));
        // (時or分or秒)針の先端のx,y座標
        pt.px[2] = centerX + (int)(typeLen  * Math.cos(angle1));
        pt.py[2] = centerY - (int)(typeLen  * Math.sin(angle1));
        // 時計の中心と針の先端以外の二つの頂点の座標(左)
        pt.px[3] = centerX + (int)(Len * Math.cos(angle1 - angle2));
        pt.py[3] = centerY - (int)(Len * Math.sin(angle1 - angle2));
        return pt;
    }

}

関連リンク

C++でのDirect2D + WIC + Windows APIでアナログ時計はこちら

C++でのシンプル実装はこちら