一個精美的java時鐘 (自動換背景 秒針平滑移動)

b4c2 10年前發布 | 4K 次閱讀 Java

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import javax.swing.JFrame; import javax.swing.JLabel;

/**

  • 一個精美的時鐘 (自動換背景 秒針平滑移動)
  • 注意:背景圖片需放在該包的image目錄下(命名:1.jpg...5.jpg) */ public class Clock extends JFrame { // 今天的日期對象 private GregorianCalendar now = new GregorianCalendar(); // 時鐘標簽,上面畫的是圓形時鐘 private ClockLabel clockLabel = new ClockLabel(); // 星期標簽,指示星期 private JLabel weekLabel = new JLabel(); // 日期標簽,指示日期 private JLabel dateLabel = new JLabel(); // 品牌標簽 private JLabel remarkLabel = new JLabel(); // 時間標簽,指示時間 private JLabel timeLabel = new JLabel();

    public Clock() {

     setTitle("時鐘");
     setSize(500, 480);
     setLocation(((int) Toolkit.getDefaultToolkit().getScreenSize()
             .getWidth() - 500) / 2, ((int) Toolkit.getDefaultToolkit()
             .getScreenSize().getHeight() - 480) / 2);
     init();
     setResizable(false);
    

    }

    private void init() {

     // 初始化品牌標簽
     remarkLabel.setText("MyClock");
     remarkLabel.setLocation(205, 80);
     remarkLabel.setSize(100, 30);
     remarkLabel.setFont(new Font("Bookman Old Style", Font.BOLD, 20));
     remarkLabel.setForeground(Color.orange);
    
     // 初始化星期標簽
     weekLabel.setSize(60, 20);
     weekLabel.setLocation(315, 190);
     weekLabel.setForeground(Color.pink);
     weekLabel.setFont(new Font("Arial Narrow", Font.BOLD, 12));
     // 為星期標簽賦值
     int week = now.get(Calendar.DAY_OF_WEEK);
     switch (week) {
     case 1:
         weekLabel.setText("SUNDAY");
         break;
     case 2:
         weekLabel.setText("MONDAY");
         break;
     case 3:
         weekLabel.setText("TUESDAY");
         break;
     case 4:
         weekLabel.setText("WEDNESDAY");
         break;
     case 5:
         weekLabel.setText("THURSDAY");
         break;
     case 6:
         weekLabel.setText("FRIDAY");
         break;
     case 7:
         weekLabel.setText("SATURDAY");
         break;
     }
    
     // 初始化日期標簽
     dateLabel.setSize(20, 20);
     dateLabel.setLocation(375, 190);
     dateLabel.setForeground(Color.pink);
     dateLabel.setFont(new Font("Fixedsys", Font.BOLD, 12));
     dateLabel.setText("" + now.get(Calendar.DATE));
    
     // 初始化時間標簽
     timeLabel.setSize(500, 30);
     timeLabel.setLocation(100, 400);
     timeLabel.setForeground(new Color(0, 64, 128));
     timeLabel.setFont(new Font("Fixedsys", Font.PLAIN, 15));
    
     // 將各組件加入到主窗口中
     Container con = getContentPane();
     con.setBackground(Color.white);
     con.setLayout(null);
     con.add(weekLabel);
     con.add(dateLabel);
     con.add(remarkLabel);
     con.add(timeLabel);
     con.add(clockLabel);
    

    }

    public static void main(String[] args) {

     Clock clock = new Clock();
     clock.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     clock.setVisible(true);
    

    }

    // 自定義時鐘標簽,畫一個圓形的時鐘 class ClockLabel extends JLabel implements Runnable {

     // 時鐘標簽的寬度和高度
     private final int WIDTH = 500;
     private final int HEIGHT = 440;
    
     // 圓形時鐘的X半徑和Y半徑
     private final int CIRCLE_X_RADIUS = 150;
     private final int CIRCLE_Y_RADIUS = 155;
    
     // 圓形時鐘的原點
     private final int CIRCLE_X = 250;
     private final int CIRCLE_Y = 200;
    
     // 圓形時鐘指針的長度
     private final int HOUR_LENGTH = 70;
     private final int MIN_LENGTH = 100;
     private final int SEC_LENGTH = 135;
    
     // 當前時針所處的角度
     double arcHour = 0;
     // 當前分針所處的角度
     double arcMin = 0;
     // 當前秒針所處的角度
     double arcSec = 0;
    
     // 顏色的透明度,
     int alpha = 60;
     // 標識顏色透明度變化的方向,為true時表示越來越透明,為false時表示月來越不透明
     boolean flag = false;
     // 背景圖片的id,輪換顯示背景圖片時使用
     int imageID = 0;
     // 背景圖片對象數組
     Image img[] = new Image[5];
     // 背景圖片URL,在該包的image目錄下(命名:1.jpg...5.jpg)
     URL url[] = new URL[] { ClockLabel.class.getResource("image/1.jpg"),
             ClockLabel.class.getResource("image/2.jpg"),
             ClockLabel.class.getResource("image/3.jpg"),
             ClockLabel.class.getResource("image/4.jpg"),
             ClockLabel.class.getResource("image/5.jpg"),
             ClockLabel.class.getResource("image/6.jpg") };
    
     // 一個具有緩沖區的圖像對象
     BufferedImage bufferedImage = null;
     int imageSize = 2 * Math.max(CIRCLE_X_RADIUS, CIRCLE_Y_RADIUS);
     // 為bufferedImage創建的Graphics對象,用于在bufferedImage上畫圖
     Graphics bufferedImageGraphics = null;
     // 時鐘線程
     Thread clockThread = null;
     // 計數器
     int count = 0;
    
     public ClockLabel() {
    
         // 設置時鐘標簽的大小
         this.setSize(WIDTH, HEIGHT);
    
         // 獲取時針、分針、秒針當前的角度
         arcHour = now.get(Calendar.HOUR) * (360.0 / 12)
                 + now.get(Calendar.MINUTE) * (360.0 / 12 / 60)
                 + now.get(Calendar.SECOND) * (360.0 / 12 / 60 / 60);
         arcMin = now.get(Calendar.MINUTE) * (360.0 / 60)
                 + now.get(Calendar.SECOND) * (360.0 / 60 / 60);
         arcSec = now.get(Calendar.SECOND) * (360.0 / 60);
    
         // 根據圖片URL創建圖片對象
         Toolkit tk = this.getToolkit();
         img[0] = tk.createImage(url[0]);
         img[1] = tk.createImage(url[1]);
         img[2] = tk.createImage(url[2]);
         img[3] = tk.createImage(url[3]);
         img[4] = tk.createImage(url[4]);
         try {
             // 使用MediaTracker加載圖片對象
             // MediaTracker 類是一個跟蹤多種媒體對象狀態的實用工具類,
             // 媒體對象可以包括音頻剪輯和圖像,但目前僅支持圖像.
             MediaTracker mt = new MediaTracker(this);
             mt.addImage(img[0], 0);
             mt.addImage(img[1], 0);
             mt.addImage(img[2], 0);
             mt.addImage(img[3], 0);
             mt.addImage(img[4], 0);
             // 加載媒體跟蹤器中所有的圖像。
             mt.waitForAll();
         } catch (Exception e) {
             e.printStackTrace();
         }
    
         // 創建一個有緩沖的Image對象
         bufferedImage = new BufferedImage(imageSize, imageSize,
                 BufferedImage.TYPE_INT_ARGB);
         // 為BufferedImage創建Graphics2D對象,
         // 以后用該Graphics2D對象畫的圖都會畫在BufferedImage中
         bufferedImageGraphics = bufferedImage.createGraphics();
    
         // 啟動線程
         clockThread = new Thread(this);
         clockThread.start();
     }
    
     public void paint(Graphics g1) {
         // Graphics2D繼承Graphics,比Graphics提供更豐富的方法
         Graphics2D g = (Graphics2D) g1;
    
         /** ***畫圓形時鐘的刻度,每6度便有一個刻度**** */
         for (int i = 0; i < 360; i = i + 6) {
             g.setColor(Color.gray);
             // 設置畫筆的寬度為2
             g.setStroke(new BasicStroke(2));
    
             // 畫刻度
             if (i % 90 == 0) {
                 // 對于0,3,6,9點位置,使用一個大的刻度
                 g.setColor(Color.pink);
                 g.setStroke(new BasicStroke(7));// 畫筆寬度為5
                 // 當起點和終點一樣時,畫的就是點
                 g.drawLine(
                         CIRCLE_X
                                 + (int) (Math.cos(i * Math.PI / 180) * CIRCLE_X_RADIUS),
                         CIRCLE_Y
                                 + (int) (Math.sin(i * Math.PI / 180) * CIRCLE_Y_RADIUS),
                         CIRCLE_X
                                 + (int) (Math.cos(i * Math.PI / 180) * CIRCLE_X_RADIUS),
                         CIRCLE_Y
                                 + (int) (Math.sin(i * Math.PI / 180) * CIRCLE_Y_RADIUS));
             } else if (i % 30 == 0) {
                 // 如果角度處于小時的位置,而且還不在0,3,6,9點時,畫紅色的小刻度
                 g.setColor(Color.orange);
                 g.setStroke(new BasicStroke(3));// 畫筆寬度為3
                 g.drawLine(
                         CIRCLE_X
                                 + (int) (Math.cos(i * Math.PI / 180) * CIRCLE_X_RADIUS),
                         CIRCLE_Y
                                 + (int) (Math.sin(i * Math.PI / 180) * CIRCLE_Y_RADIUS),
                         CIRCLE_X
                                 + (int) (Math.cos(i * Math.PI / 180) * CIRCLE_X_RADIUS),
                         CIRCLE_Y
                                 + (int) (Math.sin(i * Math.PI / 180) * CIRCLE_Y_RADIUS));
             } else {
                 // 其他位置就畫小刻度
                 g.setColor(Color.gray);
                 g.drawLine(
                         CIRCLE_X
                                 + (int) (Math.cos(i * Math.PI / 180) * CIRCLE_X_RADIUS),
                         CIRCLE_Y
                                 + (int) (Math.sin(i * Math.PI / 180) * CIRCLE_Y_RADIUS),
                         CIRCLE_X
                                 + (int) (Math.cos(i * Math.PI / 180) * CIRCLE_X_RADIUS),
                         CIRCLE_Y
                                 + (int) (Math.sin(i * Math.PI / 180) * CIRCLE_Y_RADIUS));
             }
         }
    
         /** ****** 畫時鐘的指針 ******** */
         // 畫時針
         Line2D.Double lh = new Line2D.Double(CIRCLE_X, CIRCLE_Y, CIRCLE_X
                 + Math.cos((arcHour - 90) * Math.PI / 180) * HOUR_LENGTH,
                 CIRCLE_Y + Math.sin((arcHour - 90) * Math.PI / 180)
                         * HOUR_LENGTH);
         // 設置畫筆寬度和顏色
         g.setStroke(new BasicStroke(8));
         g.setColor(Color.pink);
         // 利用Graphics2D的draw方法畫線
         g.draw(lh);
    
         // 畫分針
         Line2D.Double lm = new Line2D.Double(CIRCLE_X, CIRCLE_Y, CIRCLE_X
                 + Math.cos((arcMin - 90) * Math.PI / 180) * MIN_LENGTH,
                 CIRCLE_Y + Math.sin((arcMin - 90) * Math.PI / 180)
                         * MIN_LENGTH);
         g.setStroke(new BasicStroke(4));
         g.setColor(Color.orange);
         g.draw(lm);
    
         // 畫秒針
         Line2D.Double ls = new Line2D.Double(CIRCLE_X, CIRCLE_Y, CIRCLE_X
                 + Math.cos((arcSec - 90) * Math.PI / 180) * SEC_LENGTH,
                 CIRCLE_Y + Math.sin((arcSec - 90) * Math.PI / 180)
                         * SEC_LENGTH);
         g.setStroke(new BasicStroke(1));
    
         g.setColor(Color.lightGray);
         g.draw(ls);
    
         /** **** 畫時鐘背景,并將其透明處理 ******* */
         // 所有使用bufferedImageGraphics畫的圖像,都畫在bufferedImage上,
         // drawImage方法的參數含義分別是:背景圖片對象、目標位置第一個角的X、Y坐標、目標位置第二個角的X、Y坐標、
         // 源位置第一個角的X、Y坐標、源位置第二個角的X、Y坐標、圖像對象改變時的通知接受者
         bufferedImageGraphics.drawImage(img[imageID], 0, 0, imageSize,
                 imageSize, 0, 0, imageSize + 10, imageSize + 10, this);
         // 將背景圖片透明化
         for (int j = 0; j < imageSize; j++) {
             for (int i = 0; i < imageSize; i++) {
                 // 獲得背景圖像中(i, j)坐標的顏色值
                 int pix = bufferedImage.getRGB(i, j);
                 Color c = new Color(pix);
                 int R = c.getRed();
                 int G = c.getGreen();
                 int B = c.getBlue();
                 // 通過Color對象的alpha,使顏色透明。
                 int newpix = new Color(R, G, B, alpha).getRGB();
                 // 重新設置背景圖像該象素點的顏色
                 bufferedImage.setRGB(i, j, newpix);
             }
         }
    
         /** 以上畫背景操作都是畫在bufferedImage上的,這里要將bufferedImage畫在ClockLabel **/
         // 將當前用戶剪貼區 Clip 與橢圓區域相交,并將 Clip 設置為所得的交集
         g.clip(new Ellipse2D.Double(95, 45, imageSize, imageSize));
         g.setColor(Color.white);
         // 在用戶剪貼區畫bufferedImage
         g.drawImage(bufferedImage, 95, 45, this);
     }
    
     public void run() {
         try {
    
             while (clockThread != null) {
    
                 // 計數
                 count++;
                 // 獲得完整的日期格式
                 DateFormat df = DateFormat.getDateTimeInstance(
                         DateFormat.FULL, DateFormat.FULL);
                 // 格式化當前時間
                 String s = df.format(new Date());
                 timeLabel.setText(s);
                 // 每動一次對時鐘指針的角度進行調整
                 arcSec += 360.0 / 60 / 10; // 每秒轉6度
                 arcMin += 360.0 / 60 / 60 / 10; // 每60秒轉6度
                 arcHour += 360.0 / 12 / 60 / 60 / 10; // 每3600秒轉30度
    
                 // 當角度滿一圈時,歸0
                 if (arcSec >= 360) {
                     arcSec = 0;
                 }
                 if (arcMin >= 360) {
                     arcMin = 0;
                 }
                 if (arcHour >= 360) {
                     arcHour = 0;
                 }
                 // 實現背景透明度漸變
                 // 從淺入深,再由深入淺。
                 if (count % 2 == 0) {// 用于背景替換減速
                     if (flag) {
                         alpha += 1;
                         if (alpha == 60) {
                             flag = !flag;
                         }
                     } else {
                         alpha -= 1;
                         if (alpha == 0) {
                             flag = !flag;
                             // 當透明度變化一個輪回時,換一張背景圖
                             imageID++;
                             if (imageID == 4) {
                                 imageID = 0;
                             }
                         }
                     }
                     if (count >= 2147483647) { // 防溢出
                         count = 0;
                     }
                 }
                 // 重畫時鐘標簽
                 repaint();
    
                 // 等待0.1秒鐘
                 Thread.sleep(100);
    
             }
         } catch (Exception e) {
             e.printStackTrace();
         }
     }
    

    } }</pre>

 本文由用戶 b4c2 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!