利用Swing绘制一个动态时钟

效果

在这里插入图片描述
代码在下面,可跳过解析。

前言

编程实现一个时钟

利用Swing绘制一个时钟,只能是静态的。利用Calendar类获取当前的时分秒,然后根据数学公式绘制相应的时钟就可以了。

如果静态的时钟已经足够你使用,那么就无须用到线程的概念。

如何让时钟“动起来”

当然了,动起来肯定是不可能的,但是我们可以利用人眼的视觉,让时钟“好像动起来”,其实着很简单,只要让当前的图像每隔一秒种刷新一次就可以了。这样秒针在动,数字时间也在动,整个时钟就好像“动起来了”

线程

利用线程实现刷新,刷新间隔是1秒,每次刷新都先生成当前的时间,然后JVM又会自动调用paintComponent方法绘制图形,这样就好像时钟动起来了。

Thread thread = new Thread(){
            public void run(){
                while(true){
                    StillClock clock = new StillClock();
                    MessagePanel messagePanel1=new MessagePanel(clock.getHour()+":"+
                            clock.getMinute()+":"+clock.getSecond());
                    //设置显示居中
                    messagePanel1.setCentered(true);
                    //设置前景颜色
                    messagePanel1.setForeground(Color.black);
                    //设置字体
                    messagePanel1.setFont(new Font("Courier",Font.BOLD,16));

                    add(clock);
                    add(messagePanel1,BorderLayout.SOUTH);
                    clock.setVisible(true);
                    validate();        //接下来会每隔一秒重绘一次时钟——即(从frame中将clock组件删除),因此调用validate方法,使容器重新布置其子组件
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    clock.setVisible(false);
                    remove(clock);     //在父容器中将其删除
                    clock.invalidate();        //使容器失效
                }
            }
        };
        thread.start();

线程代码解析

Thread thread = new Thread(){};

注意结尾使用了分号,既然使用了线程,那么需要重写它的run方法:

        public void run(){}

既然想让时钟一直动起来,那么死循环是最好的选择

            while(true){}

在while里面,每次都先生成当前的时间:

	 StillClock clock = new StillClock();

这里生成了一个无参构造的StillClock类,StillClock的无参构造方法里面会自动生成当前的时间。

注意:这里的StillClock是我自己定义的,代码贴在后面,但是如果不关心他是怎么实现的,可以直接忽略原理,直接使用,包括代码里面的messagePanel也是一样的自定义类。

时间生成完了之后,把时钟图形、当前时间的字符串、布局位置利用add()方法绘制到屏幕上

   add(clock);
   add(messagePanel1,BorderLayout.SOUTH);

接下来会每隔一秒重绘一次时钟——即(从frame中将clock组件删除),因此调用validate方法,使容器重新布置其子组件。

    thread.start();

让线程开始工作把。

完整代码

DisplayClock.java:
package Test;

import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;

public class DisplayClock extends JFrame {
    public DisplayClock(){
        //创建一个现在的时间
        StillClock clock=new StillClock();
        //获取当前的时间
        clock.setCurrentTime();
        //设置时间的显示格式

        Thread thread = new Thread(){
            public void run(){
                while(true){
                    StillClock clock = new StillClock();
                    MessagePanel messagePanel1=new MessagePanel(clock.getHour()+":"+
                            clock.getMinute()+":"+clock.getSecond());
                    //设置显示居中
                    messagePanel1.setCentered(true);
                    //设置前景颜色
                    messagePanel1.setForeground(Color.black);
                    //设置字体
                    messagePanel1.setFont(new Font("Courier",Font.BOLD,16));

                    add(clock);
                    add(messagePanel1,BorderLayout.SOUTH);
                    clock.setVisible(true);
                    validate();        //接下来会每隔一秒重绘一次时钟——即(从frame中将clock组件删除),因此调用validate方法,使容器重新布置其子组件
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    clock.setVisible(false);
                    remove(clock);     //在父容器中将其删除
                    clock.invalidate();        //使容器失效
                }
            }
        };
        thread.start();
        //布局默认为BorderLayout,让显示信息在底部(即南边)

    }

    public static void main(String[] args) {
        DisplayClock frame=new DisplayClock();
        frame.setTitle("DisplayClock");
        frame.setSize(300,350);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);


    }
}
StillClock.java:
package Test;

import sun.util.calendar.Gregorian;

import javax.swing.*;
import java.awt.*;
import java.util.Calendar;
import java.util.GregorianCalendar;

public class StillClock extends JPanel {
    public int getHour() {
        return hour;
    }

    public void setHour(int hour) {
        this.hour = hour;
        repaint();
    }

    public int getMinute() {
        return minute;
    }

    public void setMinute(int minute) {
        this.minute = minute;
        repaint();
    }

    public int getSecond() {
        return second;
    }

    public void setSecond(int second) {
        this.second = second;
        repaint();
    }

    private int hour;
    private int minute;
    private int second;

    public StillClock() {
        setCurrentTime();
    }

    public StillClock(int hour, int minute, int second) {
        this.hour = hour;
        this.minute = minute;
        this.second = second;
    }

    //使用Graphics类绘制图形,需要重写paintComponent方法
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        //绘制时钟参数
        int clockRadius=(int)(Math.min(getWidth(),getHeight())*0.8*0.5);
        int xCenter=getWidth()/2;
        int yCenter=getHeight()/2;

        //绘制一个圆
        g.setColor(Color.BLACK);
        g.drawOval(xCenter-clockRadius,yCenter-clockRadius,2*clockRadius
        ,2*clockRadius);
        g.drawString("12",xCenter-5,yCenter-clockRadius+12);
        g.drawString("9",xCenter-clockRadius+3,yCenter+5);
        g.drawString("3",xCenter+clockRadius-10,yCenter
        +3);
        g.drawString("6",xCenter-3,yCenter+clockRadius-3);

        //绘制秒针
        int sLength=(int)(clockRadius*0.8);
        int xSecond=(int)(xCenter+sLength*Math.sin(second*(2*Math.PI/60)));
        int ySecond=(int)(xCenter-sLength*Math.cos(second*(2*Math.PI/60)));
        g.setColor(Color.red);
        g.drawLine(xCenter,yCenter,xSecond,ySecond);

        //绘制分针
        int mLength=(int)(clockRadius*0.65);
        int xMinute=(int)(xCenter+mLength*Math.sin(minute*(2*Math.PI/60)));
        int yMinute=(int)(xCenter-mLength*Math.cos(minute*(2*Math.PI/60)));
        g.setColor(Color.blue);
        g.drawLine(xCenter,yCenter,xMinute,yMinute);

        //绘制时针
        int hLength=(int)(clockRadius*0.5);
        int xHour=(int)(xCenter+hLength*Math.sin((hour%12+minute/60.0)*(2*Math.PI/12)));
        int yHour=(int)(xCenter-hLength*Math.cos((hour%12+minute/60.0)*(2*Math.PI/12)));
        g.setColor(Color.green);
        g.drawLine(xCenter,yCenter,xHour,yHour);


        }
    public void setCurrentTime(){
        //构造一个日历类设定当前日期和时间
        Calendar calendar=new GregorianCalendar();

        //设定时分秒
        this.hour=calendar.get(Calendar.HOUR_OF_DAY);
        this.minute=calendar.get(Calendar.MINUTE);
        this.second=calendar.get(Calendar.SECOND);
    }

    public Dimension getPreferredSize(){
        return new Dimension(200,200);
    }
}
messagePanel:
package Test;

import javax.swing.*;
import java.awt.*;

public class MessagePanel extends JPanel {
   //显示的信息
    private String message="Welcome to java";
    //显示信息x的坐标
    private int xCoordinate=20;
    //显示信息y的坐标
    private int yCoordinate=20;
    //信息是否被显示在中心部位
    private boolean centered;
    //水平和垂直的移动显示信息
    private int interval=10;

    public int getXCoordinate() {
        return xCoordinate;
    }

    public void setXCoordinate(int xCoordinate) {
        this.xCoordinate = xCoordinate;
        repaint();
    }

    //无参构造
    public MessagePanel() {
    }
    //带参构造
    public MessagePanel(String message) {
        this.message = message;
        repaint();

    }

    public int getYCoordinate() {
        return yCoordinate;
    }

    public void setYCoordinate(int yCoordinate) {
        this.yCoordinate = yCoordinate;
        repaint();

    }

    public boolean isCentered() {
        return centered;

    }

    public void setCentered(boolean centered) {
        this.centered = centered;
        repaint();

    }

    public int getInterval() {
        return interval;
    }

    public void setInterval(int interval) {
        this.interval = interval;
        repaint();

    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if(centered){
            //设定字体
            FontMetrics fm=g.getFontMetrics();
            //设置显示字体
            int stringWidth=fm.stringWidth(message);
            int stringAscent=fm.getAscent();
            xCoordinate=getWidth()/2-stringWidth/2;
            yCoordinate=getHeight()/2+stringAscent/2;
        }
        g.drawString(message,xCoordinate,yCoordinate);
    }
    //让信息往左边移动
    public void moveLeft(){
        xCoordinate-=interval;
        repaint();
}
    //让信息往右边移动
    public void moveRight(){
        xCoordinate+=interval;
        repaint();
    }
    //让信息向上移动
    public void moveUp(){
        yCoordinate+=interval;
        repaint();
    }
    public void moveDown(){
        yCoordinate-=interval;
        repaint();
    }
    //固定写法,不必探究
    @Override
    public Dimension getPreferredSize() {
        return new Dimension(200,30);
    }
}

结束

写的有些粗糙,有需要的可以根据自己的需求进行更改,比如如何更加稳定的实现动态时钟,让时钟刻度更加精细(根据数学公式增加刻度线即可),希望可以帮助到你。

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值