使用Swing繪制動態(tài)時鐘
本文實例為大家分享了利用Swing繪制一個動態(tài)時鐘的具體代碼,供大家參考,具體內(nèi)容如下
效果

代碼在下面,可跳過解析。
前言
編程實現(xiàn)一個時鐘
利用Swing繪制一個時鐘,只能是靜態(tài)的。利用Calendar類獲取當(dāng)前的時分秒,然后根據(jù)數(shù)學(xué)公式繪制相應(yīng)的時鐘就可以了。
如果靜態(tài)的時鐘已經(jīng)足夠你使用,那么就無須用到線程的概念。
如何讓時鐘“動起來”
當(dāng)然了,動起來肯定是不可能的,但是我們可以利用人眼的視覺,讓時鐘“好像動起來”,其實著很簡單,只要讓當(dāng)前的圖像每隔一秒種刷新一次就可以了。這樣秒針在動,數(shù)字時間也在動,整個時鐘就好像“動起來了”
線程
利用線程實現(xiàn)刷新,刷新間隔是1秒,每次刷新都先生成當(dāng)前的時間,然后JVM又會自動調(diào)用paintComponent方法繪制圖形,這樣就好像時鐘動起來了。
Thread thread = new Thread(){
public void run(){
while(true){
StillClock clock = new StillClock();
MessagePanel messagePanel1=new MessagePanel(clock.getHour()+":"+
clock.getMinute()+":"+clock.getSecond());
//設(shè)置顯示居中
messagePanel1.setCentered(true);
//設(shè)置前景顏色
messagePanel1.setForeground(Color.black);
//設(shè)置字體
messagePanel1.setFont(new Font("Courier",Font.BOLD,16));
add(clock);
add(messagePanel1,BorderLayout.SOUTH);
clock.setVisible(true);
validate(); //接下來會每隔一秒重繪一次時鐘——即(從frame中將clock組件刪除),因此調(diào)用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(){};
注意結(jié)尾使用了分號,既然使用了線程,那么需要重寫它的run方法:
public void run(){}
既然想讓時鐘一直動起來,那么死循環(huán)是最好的選擇
while(true){}
在while里面,每次都先生成當(dāng)前的時間:
StillClock clock = new StillClock();
這里生成了一個無參構(gòu)造的StillClock類,StillClock的無參構(gòu)造方法里面會自動生成當(dāng)前的時間。
注意:這里的StillClock是我自己定義的,代碼貼在后面,但是如果不關(guān)心他是怎么實現(xiàn)的,可以直接忽略原理,直接使用,包括代碼里面的messagePanel也是一樣的自定義類。
時間生成完了之后,把時鐘圖形、當(dāng)前時間的字符串、布局位置利用add()方法繪制到屏幕上
add(clock); add(messagePanel1,BorderLayout.SOUTH);
接下來會每隔一秒重繪一次時鐘——即(從frame中將clock組件刪除),因此調(diào)用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(){
//創(chuàng)建一個現(xiàn)在的時間
StillClock clock=new StillClock();
//獲取當(dāng)前的時間
clock.setCurrentTime();
//設(shè)置時間的顯示格式
Thread thread = new Thread(){
public void run(){
while(true){
StillClock clock = new StillClock();
MessagePanel messagePanel1=new MessagePanel(clock.getHour()+":"+
clock.getMinute()+":"+clock.getSecond());
//設(shè)置顯示居中
messagePanel1.setCentered(true);
//設(shè)置前景顏色
messagePanel1.setForeground(Color.black);
//設(shè)置字體
messagePanel1.setFont(new Font("Courier",Font.BOLD,16));
add(clock);
add(messagePanel1,BorderLayout.SOUTH);
clock.setVisible(true);
validate(); //接下來會每隔一秒重繪一次時鐘——即(從frame中將clock組件刪除),因此調(diào)用validate方法,使容器重新布置其子組件
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
clock.setVisible(false);
remove(clock); //在父容器中將其刪除
clock.invalidate(); //使容器失效
}
}
};
thread.start();
//布局默認(rèn)為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);
//繪制時鐘參數(shù)
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(){
//構(gòu)造一個日歷類設(shè)定當(dāng)前日期和時間
Calendar calendar=new GregorianCalendar();
//設(shè)定時分秒
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的坐標(biāo)
private int xCoordinate=20;
//顯示信息y的坐標(biāo)
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();
}
//無參構(gòu)造
public MessagePanel() {
}
//帶參構(gòu)造
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){
//設(shè)定字體
FontMetrics fm=g.getFontMetrics();
//設(shè)置顯示字體
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);
}
}
結(jié)束
寫的有些粗糙,有需要的可以根據(jù)自己的需求進(jìn)行更改,比如如何更加穩(wěn)定的實現(xiàn)動態(tài)時鐘,讓時鐘刻度更加精細(xì)(根據(jù)數(shù)學(xué)公式增加刻度線即可),希望可以幫助到你。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
SpringMVC如何獲取表單數(shù)據(jù)(radio和checkbox)
這篇文章主要介紹了SpringMVC如何獲取表單數(shù)據(jù)(radio和checkbox)的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07
mybatisplus下劃線駝峰轉(zhuǎn)換的問題解決
在mybatis-plus中,下劃線-駝峰自動轉(zhuǎn)換可能導(dǎo)致帶下劃線的字段查詢結(jié)果為null,本文就來介紹一下mybatisplus下劃線駝峰轉(zhuǎn)換的問題解決,感興趣的可以了解一下2024-10-10
Java?實現(xiàn)使用Comparable按照我們指定的規(guī)則排序
這篇文章主要介紹了Java?如何使用Comparable按照我們指定的規(guī)則排序,通過練習(xí)創(chuàng)建TreeSet集合使用無參構(gòu)造方法,并按照年齡從小到大的順序排序,若年齡相同再按照姓名的字母順序排序展開內(nèi)容,需要的朋友可以參考一下2022-04-04
深入淺析java web log4j 配置及在web項目中配置Log4j的技巧
這篇文章主要介紹了2015-11-11
容器環(huán)境的JVM內(nèi)存設(shè)置實踐記錄
Docker和K8S的興起,很多服務(wù)已經(jīng)運行在容器環(huán)境,對于java程序,JVM設(shè)置是一個重要的環(huán)節(jié),這里總結(jié)下我們項目里的最佳實踐,對容器環(huán)境的JVM內(nèi)存相關(guān)知識感興趣的朋友一起看看吧2022-03-03
feign實現(xiàn)傳遞參數(shù)的三種方式小結(jié)
這篇文章主要介紹了feign實現(xiàn)傳遞參數(shù)的三種方式小結(jié),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06

