java 时钟_Java的指针时钟

Java的指针时钟最基础的原理和数字时钟其实差不多,也是利用Swing的Timer计时,每隔一定时间重新绘制组件,最后重写paintComponent方法来更新界面.和之前介绍的时钟一样,为了保证时钟的正确启动和终止,需要重写组件的addNotify和removeNotify方法,在方法内加入Timer的启动和终止;最后也要重写组件getPreferredSize方法使组件的大小自动适应.

首先看最终的效果:

8fb2237426bf9776e8249a89a30e4472.png 

95ed6d8aa65e864d2e6f7083c2986c6b.png

工程的目录:

c59efa18a16dcec02373e1f53b03c4d0.png

bf4f068da3c5a1e7bb364aff79535b0d.png

其中timespinner包是时间的微调组件,这儿只是为了显示用的,和指针时钟无关,先不介绍了.

Clock包则是显示指针时钟的包,指针时钟的组件类是AnalogClock,它继承于Clock类,处理和数字时钟的基本一致,先看Clock的:

/**

* This bean to define basic properties and

behaviors of a clock, concrete

* instances will be implemented byDigitalClockand

others.

*/

publicabstractclassClockextendsJComponent {

属性也是:

/**

* Font rendering context-assumes no

default transform, anti-aliasing

* active and fractional

metrics allowed.

*/

publicstaticfinalFontRenderContextfrc=newFontRenderContext(null,

true,true);

/**

* The calendar instance

for this clock.

*/

protectedCalendarcalendar;

/**

*@see#getBgImage()

*/

protectedImagebgImage;

和数字时钟完全一样,提供基本属性和文本显示和绘制的信息容器.

再看AnalogClock:

/**

* To implement a analog-type clock.

*/

publicclassAnalogClockextendsClockimplementsActionListener {

它有两个属性:

/**

* Parts to construct this

clock.

*/

privatePartsparts=null;

/**

* A timer to run in a

independent thread.

*/

privateTimertimer=null;

一个是定时刷新时间的Timer,一个是时钟的样式.

具体方法有,

1.复写addNotify和removeNotify方法控制Timer的启动和终止.

/**

*@seejava.awt.Component#addNotify()

*/

@Override

publicvoidaddNotify() {

super.addNotify();

timer.start();

}

/**

*@seejava.awt.Component#removeNotify()

*/

@Override

publicvoidremoveNotify() {

timer.stop();

super.removeNotify();

}

2.复写getPreferredSize方法使组件自动适应大小.

/**

*/

@Override

publicDimension getPreferredSize() {

Dimension size = getSize();

size.width=parts.getSize().width;

size.height=parts.getSize().height+MARGIN;

returnsize;

}

3.复写paintComponent使修正外观

@Override

publicvoidpaintComponent(Graphics g) {

4.实现Timer必须的actionPerformed方法,做定时任务

/**

* Do transformation based

on current precise time when display.

*/

@Override

publicvoidactionPerformed(ActionEvent e) {

主要操作是取得当前时间,更新组件:

parts.doTransform(hour, minute, second, millisecond);

repaint();

// Resize this clock in time

setSize(getPreferredSize());

还有最主要的构造函数,组件的外观通过它传入,

/**

* Constructor:

* Creates an analog-type clock by

using given parts.

*/

publicAnalogClock(Parts parts) {

并且把Timer初始化:

timer=newTimer(1000,this);

到现在为止,和时间设置相关的已经完成,剩下的就是传入组件的表现Parts,使画面呈现了.

指针时钟的呈现主要使用了Parts、RotateParts、BasicParts和MyParts四个类,它们是继承关系.

其中Parts是最基本的,它主要描绘指针时钟最外层的边框、指针时钟颜色和大小,,并且提供了虚的doTransform方法供子类实现绘制;

RotateParts在Parts的基础上提供了圆心和半径把数字时钟最外层的圆的属性提供出来,并提供了画刻度的方法,没有具体的绘制;

BasicParts是主要的绘制类,它完成了指针时钟显示的大部分工作,提供时钟上的数字和时分秒指针以及指针的变换器这些基本属性,并提供了绘制数字和指针在组件上的方法,简单的继承它就可以实现一个指针时钟了,只是不够美观;

MyParts是继承于BasicParts的类,它主要目的是把指针时钟做的更美观,并且定义时钟的基本大小,颜色等,提供了更好的绘制钟面上数字和指针的方法.

现在依次详细看看这些类:

首先是最基本的Parts

/**

* To represent all modules which a analog-type clock consists

of.

*/

publicabstractclassPartsextendsJComponent {

再看看它的属性:

/**

* Coloring scheme for the

parts.

*/

protectedBasicColorcolors;

/**

* Size of this parts.

*/

protectedDimensionsize;

/**

* Clock face.

*/

protectedShapedial;

分别控制时钟的各个颜色,大小,和外观样式.

然后是方法,它提供一个虚方法给具体类实现:

/**

*

Changes positions of hour hand, minute hand, second hand and         * decisecondhand based on current time.

*/

publicabstractvoiddoTransform(inthour,intminute,intsecond,

intmillisecond);

这个方法主要是按给定的时间值得出指针在时钟上的位置和角度.

接着是RotateParts类:

/**

* This class defines a classical clock

behavior by using rotation pattern, *as we all know in common sense.

*/

publicabstractclassRotatePartsextendsParts {

再看看它的属性:

/**

* X coordinate of the

center.

*/

protectedfloatx;

/**

* Y coordinate of the

center.

*/

protectedfloaty;

/**

* Radius of the clock

face.

*/

protectedfloatradius;

分别给定了指针时钟的圆的圆心和半径,没有提供绘制方面的属性.

然后是方法,它提供了几个给定时间值换算为时钟位置的方法:

/**

* a rotation instance from

12 o'clock direction.

*/

publicAffineTransform getTransform() {

returnAffineTransform.getRotateInstance(0,x,y);

}

这个方法是提供默认的指针的位置,即绕圆心(0,0)点旋转0度,即12点位置.

接着

/**

* Sets rotation algorithm

by given value.

*/

publicvoidsetToRotation(AffineTransform af,doublevalue,intgrad) {

af.setToRotation(value * (2 * Math.PI/ grad),x,y);

}

这个方法根据给定的具体值(这里可以理解为当前具体时间的时、分或者秒)和总的时间划分(12或者60)算出需要旋转的角度,然后绕圆心(x,y)旋转.

最后是

/**

* Gets a rotation

transform by given parameters.

*/

publicAffineTransform getRotateInstance(intgrad,intseq) {

returngetRotateInstance(x,y, grad, seq);

}

/**

* Get a rotation transform

by given parameters.

*/

publicstaticAffineTransform getRotateInstance(floatx,floaty,intgrad,intseq) {

returnAffineTransform.getRotateInstance((2

* Math.PI/ grad) *

seq, x, y);

}

这个是根据指定的值和总值以及中心点取得映射变换的实例.

接着就是重要的BasicParts类了

/**

* To

implement a classical analog-type clock face, except definitely *describing the hands

shape.

*/

publicabstractclassBasicPartsextendsRotateParts {

它是钟表刻度的继承,继承它就可以实现自己的指针钟表了.

先看它的属性:

/**

* Hour hand.

*/

protectedShapehourHand;

/**

* Minute hand.

*/

protectedShapeminuteHand;

/**

* Second hand.

*/

protectedShapesecondHand;

/**

* Hour hand behavior

controller.

*/

protectedAffineTransformhourTransform;

/**

* Minute hand behavior

controller.

*/

protectedAffineTransformminuteTransform;

/**

* Second hand behavior

controller.

*/

protectedAffineTransformsecondTransform;

这6个属性提供时分秒三个时针的形状和绘制映射类,通过它们可以对钟表进行绘制.

/**

* Moves all parts, to

leave some margin.

*/

protectedtransientAffineTransformtrans;

这个属性是在对时分秒指针绘制时提供变换的.

/**

* Arabic time punctualities.

*/

publicstaticfinalString[]ARABIC= {"12","1","2","3","4","5","6","7","8","9","10","11"};

/**

* Roman time punctualities.

*/

publicstaticfinalString[]ROMAN= {"XII","I","II","III","IV","V","VI","VII","VIII","IX","X","XI"};

这两个常量是提供表盘的刻度显示的,也可以自己定义一个12位的数组代替.

再看它的构造函数

/**

* Constructor: Joins every

parts in a entire analog-type clock.

*/

protectedBasicParts(Shape dial, Shape hourHand, Shape minuteHand,

Shape secondHand, String[] numbers, BasicColor colors)

throwsException {

需要传入外围图形、时分秒图形、刻度数字和各部分颜色.当然可以传入newGeneralPath()

在以后再具体描绘它们.

/**

* Initializes hand

transformation.

*/

protectedvoidinitTransform() {

hourTransform= getTransform();

minuteTransform= getTransform();

secondTransform= getTransform();

}

这个是初始化时分秒绘制映射类的.默认让它们都指向12点方向.

/**

* Default algorithm for

hands's action trace.

*/

@Override

publicvoiddoTransform(inthour,intminute,intsecond,intmillisecond) {

if(hourTransform!=null&&minuteTransform!=null

&&secondTransform!=null) {

setToRotation(hourTransform,

hour + (minute + second / 60.0) / 60.0, 12);

setToRotation(minuteTransform, minute + second / 60.0, 60);

setToRotation(secondTransform, second, 60);

}

}

这个是父类的虚函数的实现,根据给定值旋转指定角度呈现给画面.

/**

* Draws a number at 12

o'clock.

*/

protectedvoiddrawNumber(Graphics g, String number, Font font) {

BasicColor c = (BasicColor)colors;

AttributedString num =newAttributedString(number);

if(font !=null) {

num.addAttribute(TextAttribute.FONT, font);

}

drawNumber(g,

num,x,y-radius, c.numbers);

}

/**

* Draws a number at 12

o'clock.

*/

publicstaticvoiddrawNumber(Graphics g, AttributedString number,floatx,floaty, Color color) {

if(number !=null) {

Graphics2D g2 = (Graphics2D) g;

g2.setPaint(color);

g2.drawString(number.getIterator(),

x, y);

}

}

是按指定的属性在表盘上画刻度的.

最后是重要的paintComponent方法了

@Override

publicvoidpaintComponent(Graphics g) {

它按照属性了上面取得的绘制映射类进行绘制

首先是绘制外围界面:

g2.setPaint(c.dail);

g2.fill(trans.createTransformedShape(dial));

g2.setPaint(Color.BLACK);

g2.draw(trans.createTransformedShape(dial));

然后绘制时分秒指针:

// Draw hour hand

g2.setPaint(c.hourHand);

g2.fill(trans.createTransformedShape(hourTransform

.createTransformedShape(hourHand)));

分秒基本和时的一样.

最后要看的类就是自己实现的MyParts类了,其实这里简单实现一个SimpleParts也可以的只是界面比较难看,如下图:

12.jpg

所以需要做漂亮点还是要自己去写一部分代码的.

先看继承关系

/**

* A piece of sample code to show how to

develop a nice-looking

analog-type

* clock by using this API.

*/

publicfinalclassMyPartsextendsBasicParts {

首先还是看它的属性:

/**

* Radius of the clock

face.

*/

protectedfloatradius;

这个是定义钟表的半径.

/**

* 12 hour ticks.

*/

protectedShapetick;

/**

* Other 48 minute ticks

not at time punctualities.

*/

privateGeneralPathsmallTick;

这2个是定义钟表的刻度,分别代表比较明显的12个整点刻度,和其它48个不明显的刻度.

/**

* X coordinate of left top

corner.

*/

privatestaticfloatxNW= 0;

/**

* Y coordinate of left top

corner.

*/

privatestaticfloatyNW= 0;

/**

* Width of the square.

*/

privatestaticfloatwidth= 170;

这2个属性分别代表距离中心的坐标和表的外围大小.

/**

* Additional margin size

in proportion of radius by percentage.

*/

privatestaticfloatmarginOfRadius= 0.1f;

这个属性代表空白区域的百分比.

然后是方法,先看画刻度的方法:

/**

* Draws ticks.

*/

publicstaticvoiddrawTicks(Graphics

g, Shape tick,inttickNumber,

floatx,floaty, AffineTransform trans, Color color) {

首先得到最基本的指针位置,默认指向12点位置:

AffineTransform at = AffineTransform.getRotateInstance(0, x, y);

然后取得偏移的角度:

at = RotateParts.getRotateInstance(x, y, tickNumber, p);

最后是绘制:

g2.fill(trans.createTransformedShape(at

.createTransformedShape(tick)));

再看绘制指针的方法:

/**

* Generate hour hand and

minute hand shape.

*/

privatevoidcreateHand(Shape hand,floatx,floaty,floatradius,

floatwidthPercent,floatlengthPercent,floatmarginPercent,

floatfirstWidthPercent,floatfirstLengthPercent,

floatsecondWidthPercent,floatsecondLengthPercent) {

这个是绘制时针和分针的,形状是尾部粗尖端细

h.moveTo(x, y);

h.curveTo(x - radius * (widthPercent / 2) * (firstWidthPercent / 2), y-

radius * marginPercent * (firstLengthPercent / 2), x – radius * (widthPercent /

2) * (secondWidthPercent / 2), y – radius * marginPercent *

(secondLengthPercent / 2), x, y – radius* lengthPercent);

/**

* Generates concrete hand

shape.

*/

publicstaticvoidcreateHand(Shape

hand,floatx,floaty,floatradius,floatwidthPercent,floatlengthPercent,floatmarginPercent) {

这个是绘制秒针的,粗细均匀,比较简单

h.moveTo(x - radius *

(widthPercent / 2), y + radius * marginPercent);

h.lineTo(x + radius *

(widthPercent / 2), y + radius * marginPercent);

再看绘制表上数字的方法

/**

*

An algorithm to locate time punctualities numbers on a round clock *face

*/

privatevoiddrawNumbers(Graphics g, String[] numbers,floatmarginPercent, Font font) {

以3点举例,先算角度:

floatcZero1 = (float) Math.cos((2 * Math.PI/ 12) * 3);

再把数字转为属性串,取得宽度:

num =newAttributedString(numbers[p]);

num.addAttribute(TextAttribute.FONT, font);

layout =newTextLayout(numbers[p], font, Clock.frc);

floatwidth = layout.getBounds().getBounds().width;

然后算出坐标:

floatpx = (float) (x+trans.getTranslateX() +radius

* (1 + marginPercent) * sin);

最后调用父类绘制方法绘制:

super.drawNumber(g, num, px, py, color);

接着是初始化方法,它把指针和表盘大小,位置都进行了初始化:

/**

* To initialize some

parameters and every parts shape.

*/

protectedvoidinitialize() {

首先算圆心和半径:

x=xNW+width/ 2;

y=yNW+width/ 2;

radius=width/ 2 - 5;

然后画时针:

设定各个百分比位置,然后调用时针方法

floathWidthOfRadius =

0.08f;

floathLengthOfRadius =

0.7f;

createHand(hourHand,x,y,radius, hWidthOfRadius, hLengthOfRadius,

hMarginOfRadius,

fstWidthOfRadius, fstLengthOfRadius,

sndWidthOfRadius,

sndLengthOfRadius);

其它指针也是类似画出.

最后是复写paintComponent方法,当属性变更时重新绘制指针时钟:

/**

* Paint ticks and time punctualities.

*/

@Override

publicvoidpaintComponent(Graphics g) {

在里面进行了指针数字和刻度绘制方法的调用

// Draw 12 numbers by using

specific font

drawNumbers(g,numbers,marginOfRadius,newFont("Ravie", Font.BOLD+ Font.ITALIC, 8));

// Draw 12 hour ticks, here

use SimpleParts

drawTicks(g,tick, max,x,y,trans, c.tick);

// Draw 48 minute ticks, here

use SimpleParts

drawTicks(g,smallTick, 60,x,y,trans, c.tick);

这个绘制类就完成了.

到此为止,所有的指针时钟的创立工作全部完成.

最后通过

/**

* This method shows how to

create a user defined analog-type clock

*/

privateAnalogClock getColorfulClock() {

if(colorfulClock==null) {

try{

colorfulClock=newAnalogClock(newMyParts());

}catch(Exception e) {

e.printStackTrace();

}

}

returncolorfulClock;

}

就可以使用了.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值