使用Swing绘制动态时钟

作者:欧世乐 时间:2023-11-24 07:05:12 

本文实例为大家分享了利用Swing绘制一个动态时钟的具体代码,供大家参考,具体内容如下

效果

使用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);
 }
}

结束

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

来源:https://blog.csdn.net/qq_43576028/article/details/100939397

标签:Swing,动态时钟
0
投稿

猜你喜欢

  • java String的intern方法

    2021-07-05 03:23:52
  • Android使用注解代替枚举节省系统内存开销的方法

    2021-09-28 18:46:06
  • Android中ProgressBar用法简单实例

    2022-09-21 05:27:55
  • IntelliJ IDEA如何设置JDK版本

    2022-08-27 07:46:03
  • Flutter WebView 预加载实现方法(Http Server)

    2023-06-25 23:14:35
  • 解决@Transactional注解事务不回滚不起作用的问题

    2022-10-29 09:18:51
  • Android 通过productFlavors实现多渠道打包方法示例

    2022-08-27 16:04:35
  • Android使用SoundPool播放短音效

    2022-03-02 12:33:00
  • C# 模式匹配完全指南

    2023-11-01 17:55:52
  • activemq整合springboot使用方法(个人微信小程序用)

    2023-07-08 22:29:55
  • 详解Maven私 服Nexus的安装与使用

    2023-11-24 12:34:02
  • Java关键字、标识符、常量、变量语法详解

    2023-11-11 20:49:48
  • Java HelloWorld原理分析_动力节点Java学院整理

    2023-05-23 21:34:14
  • Spring Boot详解创建和运行基础流程

    2022-01-28 19:57:05
  • Android 两个Fragment之间传递数据实例详解

    2022-06-23 19:30:09
  • c#创建浮动工具栏功能示例

    2022-08-31 01:08:31
  • java jpa如何自定义sql语句

    2022-08-04 14:36:52
  • C#实现彻底删除文件的方法

    2022-06-25 22:40:29
  • java语言自行实现ULID过程底层原理详解

    2023-04-13 22:38:50
  • C语言中的回调函数实例

    2021-09-27 08:37:12
  • asp之家 软件编程 m.aspxhome.com