[原创]用低级UI画windows中的时钟

来源:百度文库 编辑:神马文学网 时间:2024/07/07 09:53:54

[原创]用低级UI画windows中的时钟


双击windows任务栏上的时间,会弹出一个窗口, 上面一个时钟非常好看, 时针、分针、秒针时刻在行走,很有动感.
其实, 用低级UI完全可以画出相同的效果.
好了, 代码给出, 有兴趣的自己完善一下, 低级UI是很强的. 
public class MyTime extends Canvas implements CommandListener, Runnable
{
private Display display = null;
private ChoiceList choiceList = null;
private Command cmd_back = null;
private Command cmd_stop = null;
private Command cmd_start = null;
private String myTime = null;
private Thread thread = null;
private int width; //屏幕宽
private int height; //屏幕高
private int size; //时钟的大小,直径
private int sl; //秒针长
private int ml; //分针长
private int hl; //时针长
int pointX ; //时钟圆点的横坐标
int pointY ; //时钟圆点的纵坐标
private int sx; //秒针头的横坐标
private int sy; //秒针头的纵坐标
private int mx; //分针头的横坐标
private int my; //分针头的纵坐标
private int hx; //时针头的横坐标
private int hy; //时针头的纵坐标
private int gm; //时区偏移量,东8区gm=8,西8区gm=-8
private int timeOut;

private boolean stop;

public MyTime(Display display, ChoiceList choiceList)
{
this.display = display;
this.choiceList = choiceList;

myTime = "00:00:00";
timeOut = 1000;
width = getWidth();
height = getHeight();
size = width/2;
stop = false;
sl = size/2 -10;
ml = sl - 10;
hl = ml - 10;
pointX = width/2;
pointY = height/4 + size/2;
sx = 0;
sy = 0;
mx = 0;
my = 0;
hx = 0;
hy = 0;
gm = 8;

cmd_back = new Command("back", Command.BACK, 1);
cmd_stop = new Command("stop", Command.STOP, 1);
cmd_start = new Command("start", Command.OK, 1);
addCommand(cmd_back);
addCommand(cmd_stop);
setCommandListener(this);
thread = new Thread(this);
thread.start();
}

protected void paint(Graphics g)
{
clear(g);

g.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD,
Font.SIZE_LARGE));
g.drawString(myTime, width/2, height / 8, Graphics.HCENTER
| Graphics.BOTTOM);

//画时钟上的时刻
double tmp = Math.PI/180.0;
for (int i=0;i<60;i++)
{
int d =0; //d是小点的直径
if (i%5 == 0)
{
d = 6; //整点的直径大一点
g.setColor(0, 125, 125);
}
else 
{
d = 4; //非整点的直径小点
g.setColor(75, 125, 125);
}
int px = (int)(Math.cos((i*6.0 - 90)*tmp)*size/2 + pointX);
int py = (int)(Math.sin((i*6.0 - 90)*tmp)*size/2 + pointY);
g.fillArc(px - d/2, py - d/2, d, d, 0, 360);
}

// 画秒针
g.drawLine(pointX, pointY, sx, sy);

g.setColor(0, 125, 125);

for (int i=0;i<3;i++)
{
//分针画3遍,加粗,每次略有偏移
g.drawLine(pointX-1+i, pointY-1+i, mx, my);
}

for (int i=0;i<3;i++)
{
//时针画3遍,加粗
g.drawLine(pointX-1+i, pointY-1+i, hx, hy);
}

}

public void commandAction(Command cmd, Displayable dis)
{
if (cmd == cmd_back)
{
display.setCurrent(choiceList);
}
else if (cmd == cmd_stop)
{
stop = true;
this.removeCommand(cmd_stop);
addCommand(cmd_start);
setCommandListener(this);
}
else if (cmd == cmd_start)
{
Thread newThread = new Thread(this);
stop = false;
newThread.start();
removeCommand(cmd_start);
addCommand(cmd_stop);
setCommandListener(this);
}
}

public void clear(Graphics g)
{
g.setColor(255, 255, 255);
g.fillRect(0, 0, getWidth(), etHeight());
g.setColor(0, 0, 0);
}

public void run()
{
while (!stop)
{
long start = System.currentTimeMillis();
Date date = new Date(start + gm*60*60*1000);

myTime = date.toString();

setTimeNo();
repaint();
long next = System.currentTimeMillis();
if (next - start < timeOut)
{
try
{
Thread.sleep(timeOut + start - next);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}

//得到小时数,分钟数,秒数
private void setTimeNo()
{
int second = 0;
int minute = 0;
int hour = 0;
int index = myTime.indexOf(":");

//这是秒,如08代表第8秒
String tmp1 = "" + myTime.charAt(index+4) + myTime.charAt(index+5);

//这是分,08代表第8分
String tmp2 = "" + myTime.charAt(index+1) + myTime.charAt(index+2);

//这是小时,08代表8点
String tmp3 = "" + myTime.charAt(index-2) + myTime.charAt(index-1);

myTime = tmp3+" : "+tmp2+" : "+tmp1; //只显示时间,不显示日期和星期

if (tmp1.startsWith("0"))
{
second = Integer.parseInt(tmp1.substring(1));
}
else
{
second = Integer.parseInt(tmp1);
}
if (tmp2.startsWith("0"))
{
minute = Integer.parseInt(tmp2.substring(1));
}
else 
{
minute = Integer.parseInt(tmp2);
}
if (tmp3.startsWith("0"))
{
hour = Integer.parseInt(tmp3.substring(1));
}
else 
{
hour = Integer.parseInt(tmp3);
hour %= 12; //将24小时时间化为12小时,显示在时钟上
}

setPoint(second, minute, hour);
}

//设置三个针头的点的坐标
private void setPoint(int second,int minute,int hour)
{
//经过坐标系的移动计算之后的秒针头点的坐标,
//之所以加pointX和pointY是坐标系移动的结果
//second*6 = second*360(度)/60(秒)是这样算出来的
//tmp是将弧度转化为角度
//乘上的sl是指针的长度,这是计算针头坐标必须的 
//纵坐标加负号是因为坐标系翻转
//手机屏幕坐标系的原点在左上角,所以和数学中的坐标要经过翻转才能吻合
double tmp = Math.PI/180.0;
sx = (int)(Math.cos((second*6.0 - 90)*tmp)*sl + pointX);
sy = (int)(Math.sin((second*6.0 - 90)*tmp)*sl + pointY);

//经过坐标系的移动计算之后的分针头点的坐标,
//second/60.0是指针偏移的修正值(修正值的概念在数值计算中是很常见的,这里用这个概念表达上会比较准确,但难于理解)
mx = (int)(Math.cos(((minute + second/60.0)*6.0 - 90)*tmp)*ml + pointX);
my = (int)(Math.sin(((minute + second/60.0)*6.0 - 90)*tmp)*ml + pointY);

//经过坐标系的移动计算之后的时针头点的坐标,
//minute/60.0是指针偏移的修正值
hx = (int)(Math.cos(((hour + minute/60.0)*30.0 - 90)*tmp)*hl + pointX);
hy = (int)(Math.sin(((hour + minute/60.0)*30.0 - 90)*tmp)*hl + pointY);

}
}
值得一说的是, 程序中有一个属性是时区,在模拟机和手机上运行时,可能有时需要+8小时,有时不需要,相信大家能搞定这个问题的.
在这里就不赘述了.

有网友指出choiceLIst的问题, 其实看看commandAction中你就明白了, 这是上级菜单, 用来返回的上级菜单.

这个程序是我练习的, 没有用MVC模式, 直接就返回上级菜单了.


[此贴子已经被作者于2008-10-30 8:51:22编辑过]