使用Swing繪制動(dòng)態(tài)時(shí)鐘
本文實(shí)例為大家分享了利用Swing繪制一個(gè)動(dòng)態(tài)時(shí)鐘的具體代碼,供大家參考,具體內(nèi)容如下
效果
代碼在下面,可跳過(guò)解析。
前言
編程實(shí)現(xiàn)一個(gè)時(shí)鐘
利用Swing繪制一個(gè)時(shí)鐘,只能是靜態(tài)的。利用Calendar類獲取當(dāng)前的時(shí)分秒,然后根據(jù)數(shù)學(xué)公式繪制相應(yīng)的時(shí)鐘就可以了。
如果靜態(tài)的時(shí)鐘已經(jīng)足夠你使用,那么就無(wú)須用到線程的概念。
如何讓時(shí)鐘“動(dòng)起來(lái)”
當(dāng)然了,動(dòng)起來(lái)肯定是不可能的,但是我們可以利用人眼的視覺(jué),讓時(shí)鐘“好像動(dòng)起來(lái)”,其實(shí)著很簡(jiǎn)單,只要讓當(dāng)前的圖像每隔一秒種刷新一次就可以了。這樣秒針在動(dòng),數(shù)字時(shí)間也在動(dòng),整個(gè)時(shí)鐘就好像“動(dòng)起來(lái)了”
線程
利用線程實(shí)現(xiàn)刷新,刷新間隔是1秒,每次刷新都先生成當(dāng)前的時(shí)間,然后JVM又會(huì)自動(dòng)調(diào)用paintComponent方法繪制圖形,這樣就好像時(shí)鐘動(dòng)起來(lái)了。
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(); //接下來(lái)會(huì)每隔一秒重繪一次時(shí)鐘——即(從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é)尾使用了分號(hào),既然使用了線程,那么需要重寫它的run方法:
public void run(){}
既然想讓時(shí)鐘一直動(dòng)起來(lái),那么死循環(huán)是最好的選擇
while(true){}
在while里面,每次都先生成當(dāng)前的時(shí)間:
StillClock clock = new StillClock();
這里生成了一個(gè)無(wú)參構(gòu)造的StillClock類,StillClock的無(wú)參構(gòu)造方法里面會(huì)自動(dòng)生成當(dāng)前的時(shí)間。
注意:這里的StillClock是我自己定義的,代碼貼在后面,但是如果不關(guān)心他是怎么實(shí)現(xiàn)的,可以直接忽略原理,直接使用,包括代碼里面的messagePanel也是一樣的自定義類。
時(shí)間生成完了之后,把時(shí)鐘圖形、當(dāng)前時(shí)間的字符串、布局位置利用add()方法繪制到屏幕上
add(clock); add(messagePanel1,BorderLayout.SOUTH);
接下來(lái)會(huì)每隔一秒重繪一次時(shí)鐘——即(從frame中將clock組件刪除),因此調(diào)用validate方法,使容器重新布置其子組件。
thread.start();
讓線程開(kāi)始工作把。
完整代碼
DisplayClock.java:
package Test; import javax.swing.*; import javax.swing.border.Border; import java.awt.*; public class DisplayClock extends JFrame { public DisplayClock(){ //創(chuàng)建一個(gè)現(xiàn)在的時(shí)間 StillClock clock=new StillClock(); //獲取當(dāng)前的時(shí)間 clock.setCurrentTime(); //設(shè)置時(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(); //接下來(lái)會(huì)每隔一秒重繪一次時(shí)鐘——即(從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í)鐘參數(shù) int clockRadius=(int)(Math.min(getWidth(),getHeight())*0.8*0.5); int xCenter=getWidth()/2; int yCenter=getHeight()/2; //繪制一個(gè)圓 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); //繪制時(shí)針 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)造一個(gè)日歷類設(shè)定當(dāng)前日期和時(shí)間 Calendar calendar=new GregorianCalendar(); //設(shè)定時(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; //水平和垂直的移動(dòng)顯示信息 private int interval=10; public int getXCoordinate() { return xCoordinate; } public void setXCoordinate(int xCoordinate) { this.xCoordinate = xCoordinate; repaint(); } //無(wú)參構(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); } //讓信息往左邊移動(dòng) public void moveLeft(){ xCoordinate-=interval; repaint(); } //讓信息往右邊移動(dòng) public void moveRight(){ xCoordinate+=interval; repaint(); } //讓信息向上移動(dòng) 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)定的實(shí)現(xiàn)動(dòng)態(tài)時(shí)鐘,讓時(shí)鐘刻度更加精細(xì)(根據(jù)數(shù)學(xué)公式增加刻度線即可),希望可以幫助到你。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Java實(shí)現(xiàn)動(dòng)態(tài)數(shù)字時(shí)鐘
- Java實(shí)現(xiàn)動(dòng)態(tài)模擬時(shí)鐘
- Java實(shí)現(xiàn)的動(dòng)態(tài)數(shù)字時(shí)鐘功能示例【顯示世界時(shí)間】
- Java實(shí)現(xiàn)的簡(jiǎn)單數(shù)字時(shí)鐘功能示例
- java實(shí)現(xiàn)動(dòng)態(tài)時(shí)鐘并設(shè)置鬧鐘功能
- Java編程小實(shí)例—數(shù)字時(shí)鐘的實(shí)現(xiàn)代碼示例
- java多線程編程制作電子時(shí)鐘
- java實(shí)現(xiàn)的小時(shí)鐘示例分享
相關(guān)文章
SpringBoot和前端Vue的跨域問(wèn)題及解決方案
所謂跨域就是從 A 向 B 發(fā)請(qǐng)求,如若他們的地址協(xié)議、域名、端口都不相同,直接訪問(wèn)就會(huì)造成跨域問(wèn)題,跨域是非常常見(jiàn)的現(xiàn)象,這篇文章主要介紹了解決SpringBoot和前端Vue的跨域問(wèn)題,需要的朋友可以參考下2023-11-11使用SpringBoot中web項(xiàng)目推薦目錄結(jié)構(gòu)的問(wèn)題
這篇文章主要介紹了SpringBoot中web項(xiàng)目推薦目錄結(jié)構(gòu)的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-01-01使用SpringBoot 工廠模式自動(dòng)注入到Map
這篇文章主要介紹了使用SpringBoot 工廠模式自動(dòng)注入到Map,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09一文搞清楚Java中Comparable和Comparator的區(qū)別
Java中的Comparable和Comparator都是用于集合排序的接口,但它們有明顯的區(qū)別,文中通過(guò)一些實(shí)例代碼詳細(xì)介紹了Java中Comparable和Comparator的區(qū)別,感興趣的同學(xué)跟著小編一起學(xué)習(xí)吧2023-05-05