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(); |
} |
} |
} |
} |
高级设计师
by: 小蜜锋 发表于:2012-11-15 17:48:41 顶(9) | 踩(0) 回复
代码右上角有一个工具条,请在那里点击复制代码,而不要直接复制。
回复评论