使用Swing绘制动态时钟
作者:欧世乐 发布时间:2023-11-24 07:05:12
本文实例为大家分享了利用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


猜你喜欢
- 最近公司要求开发工具要用Idea,作为一个eclipse的老员工,记录一下Idea中遇到的坑刚开始用Idea从Git上导入一个项目时,遇到了
- 前言本文主要给大家介绍了关于Android模仿美团顶部滑动菜单的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。先
- 本文介绍了Android:利用SharedPreferences实现自动登录,具体如下:主要代码:public class LoginAct
- 目录I. 项目环境1. 项目依赖II. 缓存注解介绍1. @Cacheable2. @CachePut3. @CacheEvict4. @C
- 首先我们在项目中导入这个框架:implementation 'com.mcxiaoke.volley:library:1.0.19&
- 在做相机开发时,遇到一个问题,就是需要监听屏幕旋转。最简单的就是使用onConfigurationChanged()和Orientation
- Spring容器可以自动装配相互协作bean之间的关系,这有助于减少对XML配置,而无需编写一个大的基于Spring应用程序的较多的<
- 一、在JAVA开发领域,目前可以通过以下几种方式进行定时任务1、单机部署模式Timer:jdk中自带的一个定时调度类,可以简单的实现按某一频
- Android 捕获运行时异常详解Android 异常分为两类:CheckedException 和 UnCheckedExceptionC
- 序列化是将一个对象转换成字节流以达到将其长期保存在内存、数据库或文件中的处理过程。它的主要目的是保存对象的状态以便以后需要的时候使用。与其相
- 本文实例总结了C#配置文件Section节点处理方法。分享给大家供大家参考。具体如下:很多时候在项目开发中,我们都需要用配置文件来存储一些关
- JetpackJetpack,我觉得翻译为“飞行器”更好听,因为Google针对编程历史乱象,整理出
- 在很多场景下,maven不能直接访问到外网时,使用代理是其中常见的一种方式。这篇文章整理一下常见的maven中设置代理的方法。代理服务器代理
- 本文实例讲述了C#实现文件断点续传下载的方法。分享给大家供大家参考。具体实现方法如下:using System;using System.D
- 先附spring各版本jar包下载链接http://repo.spring.io/release/org/springframework/s
- public static boolean isMobileNumber(String mobiles) {return Pattern.c
- indexof方法:注解:indexOf 方法返回一个整数值,指出 String 对象内子字符串的开始位置。如果没有找到子字符串,则返回-1
- 声明:作者是根据 Hongyang的博客自己实践之后,根据自己的理解写的,有什么不对的地方还望指正。 先放两张效果图 一、准备由于Andro
- 场景网站智能问答场景,需要对多个分类查询,结果聚合展示由于每种分类都有自己的业务逻辑,有的需要查询数据库中间库,有的需要查询elastics
- 在界面设计中,一个容器要放置许多组件,为了美观,为组件安排在容器中的位置,这就是布局设计。java.awt中定义了多种布局类,每种布局类对应