前言:

       钟表作为我们日常随处可见的生活物品,在过去几十年里,起到了很重要的标记时间的作用。如今,随着智能手机的普及,它更作为装饰品出现在房间。那么在学完Java,我们能否用程序实现一个图形化的钟表呢?

 代码:

import java.awt.*;
import java.awt.geom.Line2D;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Clock extends JPanel implements Runnable {
    private Thread thread=new Thread(this);
    private SimpleDateFormat dateFormat;
    private Point center;


    public Clock() {
        //设置面板尺寸
        setPreferredSize(new Dimension(200, 200));
        //设置背景颜色
        setBackground(Color.WHITE);
        //格式化时间
        dateFormat = new SimpleDateFormat("hh:mm:ss");
        //创建一个Point类,表示圆心
        center = new Point(100, 100);
        //启动线程
        thread.start();
    }


    //线程保证时钟运行状态不断更新
    @Override
    public void run() {
        while (true) {
            try {
                //每一秒钟更新重绘一次
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            repaint();
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        //创建一个g2d画笔
        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        //Calendar是一个抽象类,所以通过getInstance()方法来获取Calendar对象
        Calendar now = Calendar.getInstance();
        //获取时间
        int hour = now.get(Calendar.HOUR);
        int minute = now.get(Calendar.MINUTE);
        int second = now.get(Calendar.SECOND);
        //绘制表面
        drawClockFace(g2d);
        //绘制钟表的指针
        drawHand(g2d, (hour + minute / 60.0) * 30, 50, Color.BLACK, 6);
        drawHand(g2d, minute * 6, 80, Color.BLUE, 4);
        drawHand(g2d, second * 6, 90, Color.RED, 2);
        //释放资源
        g2d.dispose();
    }

    //绘制表面的方法
    private void drawClockFace(Graphics2D g2d) {
        g2d.setColor(Color.BLACK);
        //设置画笔粗细
        g2d.setStroke(new BasicStroke(2));

        Font font = new Font("黑体", Font.PLAIN, 12);
        g2d.setFont(font);

        //绘制刻度和数字

        for (int i = 1; i <= 60; i++) {
            //将角度制转化为弧度制
            double angle = i * 6 * Math.PI / 180;
            //如果是5的倍数则说明是小时数字,刻度线需要更长一些
            int length = i % 5 == 0 ? 10 : 5;
            //计算刻度线的坐标。
            //得到角度的三角函数值,再乘以半径,得到刻度线的起点和终点坐标
            int x1 = (int) (center.x + Math.sin(angle) * 80);
            int y1 = (int) (center.y - Math.cos(angle) * 80);
            int x2 = (int) (center.x + Math.sin(angle) * (80 - length));
            int y2 = (int) (center.y - Math.cos(angle) * (80 - length));
            if (i % 5 == 0) {
                String str = Integer.toString(i / 5);
                //获取字符串的高度和宽度
                int strWidth = g2d.getFontMetrics().stringWidth(str);
                int strHeight = g2d.getFontMetrics().getAscent();
                //将字符串画在表盘上
                g2d.drawString(str, x2 - strWidth / 2, y2 + strHeight / 2);
            }
            //将刻度线的始末坐标用线连起来
            g2d.draw(new Line2D.Double(x1, y1, x2, y2));
        }
        //绘制一个圆
        g2d.drawOval(center.x - 90, center.y - 90, 180, 180);
    }

    //绘制指针的方法
    private void drawHand(Graphics2D g2d, double angle, int length, Color color, int width) {
        g2d.setColor(color);
        g2d.setStroke(new BasicStroke(width));
        //将角度转换为弧度,并计算出指针末尾的坐标
        int x2 = (int) (center.x + Math.sin(angle*Math.PI / 180) * length);
        int y2 = (int) (center.y - Math.cos(angle*Math.PI / 180) * length);
        //绘制从钟表中心到指针末尾的直线
        g2d.drawLine(center.x, center.y, x2, y2);
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("Clock");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(new Clock());
        frame.setLocation(600,300);
        //自动调整窗口大小
        frame.pack();
        frame.setVisible(true);
    }
}

思路分析:

        既然我们要实现一个钟表,我们首先先要知道我们要做什么,捋清思路。

  1. 如何绘制表盘?
  2. 如何绘制指针?
  3. 如何让指针正确地转动?            

         总的来说,我们只需要解决以上3个问题,实现一个钟表便轻而易举。接下来,我们进行逐一解决。

如何绘制表盘?

        首先,一个表盘,需要画一个圆,然后再在圆上画出相应的刻度线。

        圆很好画,直接使用 g2d自带的drawOval()方法,规定圆心坐标及半径即可。

        接下来,开始画刻度线。一圈有60个刻度线,12个大刻度线(每5个刻度就有一个大刻度线,所以可以直接遍历i%5),其余的都是小刻度线,我们可以直接遍历从i=1到i=60。

        可是,如何才能把它绕一圈画在圆上?每个刻度线的间隔是360/60=6°,也就是每6°要画一个刻度线,我们可以找出该刻度线的起始坐标和末端坐标,然后用drawLine()方法,连接两个坐标。

        下一个问题,如何计算出刻度线对应的坐标?利用简单的三角函数,我画了个图。

java 写秒表 java写时钟_java


        设置好圆心的坐标后,可以在直角三角形里,通过三角函数值和半径计算出Δx和Δy,根据圆心坐标一次计算出所有刻度线的起始坐标和末坐标,最后通过将起始坐标和末坐标连起来。这样,刻度线就绘画完成。 

        具体这样实施:

private void drawClockFace(Graphics2D g2d) {
        g2d.setColor(Color.BLACK);
        //设置画笔粗细
        g2d.setStroke(new BasicStroke(2));

        Font font = new Font("黑体", Font.PLAIN, 12);
        g2d.setFont(font);

        //绘制刻度和数字

        for (int i = 1; i <= 60; i++) {
            //将角度制转化为弧度制
            double angle = i * 6 * Math.PI / 180;
            //如果是5的倍数则说明是小时数字,刻度线需要更长一些
            int length = i % 5 == 0 ? 10 : 5;
            //计算刻度线的坐标。
            //得到角度的三角函数值,再乘以半径,得到刻度线的起点和终点坐标
            int x1 = (int) (center.x + Math.sin(angle) * 80);
            int y1 = (int) (center.y - Math.cos(angle) * 80);
            int x2 = (int) (center.x + Math.sin(angle) * (80 - length));
            int y2 = (int) (center.y - Math.cos(angle) * (80 - length));
            if (i % 5 == 0) {
                String str = Integer.toString(i / 5);
                //获取字符串的高度和宽度
                int strWidth = g2d.getFontMetrics().stringWidth(str);
                int strHeight = g2d.getFontMetrics().getAscent();
                //将字符串画在表盘上
                g2d.drawString(str, x2 - strWidth / 2, y2 + strHeight / 2);
            }
            //将刻度线的始末坐标用线连起来
            g2d.draw(new Line2D.Double(x1, y1, x2, y2));
        }
        //绘制一个圆
        g2d.drawOval(center.x - 90, center.y - 90, 180, 180);
    }

 

如何绘制指针?

        其实指针的绘制和刻度线的绘制方法类似。利用计算坐标,再将坐标和圆心相连,即可画出指针,不同的指针可以通过指针粗细和颜色来区分。 具体实施代码如下:


private void drawHand(Graphics2D g2d, double angle, int length, Color color, int width) {
        g2d.setColor(color);
        g2d.setStroke(new BasicStroke(width));
        //将角度转换为弧度,并计算出指针末尾的坐标
        int x2 = (int) (center.x + Math.sin(angle*Math.PI / 180) * length);
        int y2 = (int) (center.y - Math.cos(angle*Math.PI / 180) * length);
        //绘制从钟表中心到指针末尾的直线
        g2d.drawLine(center.x, center.y, x2, y2);
    }

         通过改变传入方法参数的不同,来决定是什么指针。

 如何让指针正确地转动?

        我们首先需要通过Calendar类来获取当前日历,得到当前的小时、分钟和秒钟。然后依此绘制指针。

        秒针:秒针一秒只走6°,所以:

drawHand(g2d, second * 6, 90, Color.RED, 2);

        分针:和秒针一样,一分钟走6°,所以:

 

drawHand(g2d, minute * 6, 80, Color.BLUE, 4);

        时针:因为时针和其它两个不同,它每次转动一定是转过5个刻度线,也就是30°,所以:

drawHand(g2d, (hour + minute / 60.0) * 30, 50, Color.BLACK, 6);

        最后,指针应该是一直转动的,我们可以通过一个单线程在死循环内不断地重绘表盘即可。

@Override public void run() { while (true) { try { //每一秒钟更新重绘一次 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } repaint(); } }

        如此,用Java实现一个简单的图形化钟表就完成啦!

        我们用到的知识不多,包括swing和线程。

        难一点的主要还是在绘制表盘和指针那里的算法。所以,要多刷算法题哦qaq。