一个精美的java时钟 (自动换背景 秒针平滑移动)

清华大佬耗费三个月吐血整理的几百G的资源,免费分享!....>>>

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();
			}
		}
	}
}