这个简单的Java计时器和Java数字时钟的原理差不多,都是利用Java的Timer做计时,然后根据当前的时间生成需要显示的图片或者文字,通过重写paintComponent方法呈现在界面上.
先看看效果:
![](https://i-blog.csdnimg.cn/blog_migrate/803a11d252ba37d634c5ab911d4b2d6b.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/a3ed09cb91797369a701394781b9f3de.jpeg)
<!--[if gte vml 1]> <![endif]-->
<!--[if gte vml 1]> <![endif]-->
基本的工程目录结构如下:
![](https://i-blog.csdnimg.cn/blog_migrate/2f3b4da0ec6ec0ae8a457587f2cc75fc.jpeg)
<!--[if gte vml 1]> <![endif]-->
其中MissionTimerPanel是主要的类,它主要提供了计时器显示数字的绘制,计时器背景的绘制,计时器闪烁的点的绘制,同时使用Swing的Timer使界面的时间发生改变,最终调用Java的重绘,通过paintComponent方法刷新界面.
先写一下它的继承关系:
publicclass MissionTimerPanel extends JPanel implements ActionListener, MouseListener {
看一下它的主要属性字段:
/** the image of number 0~9 */
privatefinal BufferedImage[] DIGIT_ARRAY = { createDigit(0),
createDigit(1), createDigit(2), createDigit(3), createDigit(4), createDigit(5), createDigit(6), createDigit(7), createDigit(8), createDigit(9) };
/** the image of the dots display */
privatefinal BufferedImage DOTS_ON = createDots(true);
/** the image of the dots disappear */
privatefinal BufferedImage DOTS_OFF = createDots(false);
/** the image of panel background */
privatefinal BufferedImage BACKGROUND_IMAGE = createBackground(450, 180);
/** mission timer */
privatefinal Timer TIMER = new Timer(500, this);
分别定义了数字的图片,点的图片,背景图片和Timer.
通过构造函数设置大小和增加鼠标监听:
public MissionTimerPanel() {
setPreferredSize(new Dimension(450, 180));
setSize(new Dimension(450, 180));
addMouseListener(this);
}
然后是绘制数字的方法
// create digit with given number.
private BufferedImage createDigit(int digit) {
首先通过Java的GraphicsEnvironment取得GraphicsConfiguration,创建图片:
GraphicsConfiguration gfxConf = GraphicsEnvironment
.getLocalGraphicsEnvironment().getDefaultScreenDevice()
.getDefaultConfiguration();
BufferedImage IMAGE = gfxConf.createCompatibleImage(46, 65,
Transparency.TRANSLUCENT);
然后创建图片的绘制样式和上下文:
Graphics2D g2 = (Graphics2D) IMAGE.getGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_PURE);
g2.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_DITHERING,
RenderingHints.VALUE_DITHER_ENABLE);
g2.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
接着开始创建数字组成的线,每个数字组成都是8这个数字的一份,所以先绘制一下8所需要的所有线段:
GeneralPath segment_a = new GeneralPath();
segment_a.moveTo(17, 0);
segment_a.lineTo(38, 0);
segment_a.lineTo(37, 8);
segment_a.lineTo(16, 8);
segment_a.closePath();
这是其中一条,其它的也类似.
最后就是根据数字使用上面的线条绘制指定的图片了:
case 2:
g2.setColor(COLOR_ON);
g2.fill(segment_a);
g2.fill(segment_b);
g2.fill(segment_d);
g2.fill(segment_e);
g2.fill(segment_g);
g2.setColor(COLOR_OFF);
g2.fill(segment_c);
g2.fill(segment_f);
g2.setColor(FRAME_COLOR_ON);
g2.draw(segment_a);
g2.draw(segment_b);
g2.draw(segment_d);
g2.draw(segment_e);
g2.draw(segment_g);
g2.setColor(FRAME_COLOR_OFF);
g2.draw(segment_c);
g2.draw(segment_f);
break;
这是2的绘制,其它的也类似,这样就生成了所有的数字.
然后是绘制点的方法:
private BufferedImage createDots(boolean on) {
它和绘制数字基本一致,也是通过Java的GraphicsEnvironment取得GraphicsConfiguration,创建图片,然后创建图片的绘制样式和上下文,最后画点:
g2.setColor(COLOR_ON);
g2.fillOval(8, 20, 7, 7);
g2.fillOval(5, 39, 7, 7);
g2.setColor(FRAME_COLOR_ON);
g2.drawOval(8, 20, 7, 7);
g2.drawOval(5, 39, 7, 7);
接着是绘制背景的颜色、字和图片:
private BufferedImage createBackground(int width, int height) {
前面创建图片和设置样式和绘制数字和点的基本一致,只是使用了LinearGradientPaint进行颜色渐变的绘制:
final LinearGradientPaint GRADIENT_HIGHLIGHT = new LinearGradientPaint(START_HIGHLIGHT, STOP_HIGHLIGHT, FRACTIONS_HIGHLIGHT, COLORS_HIGHLIGHT);
g2.setPaint(GRADIENT_HIGHLIGHT);
g2.fillRect(17, 79, 176, 87);
g2.fillRect(193, 79, 239, 87);
最后把对应的显示字绘制上:
g2.drawString("HOURS", 75, 65);
这样所有的绘制图片就结束了.
然后是处理组件的监听:
@Override
publicvoid mouseClicked(MouseEvent event) {
当鼠标点击组件时启动Timer,再次点击终止Timer
if (event.getButton() == MouseEvent.BUTTON1) {
if (TIMER.isRunning()) {
stopTimer();
} else {
startTimer();
}
if (event.getClickCount() == 2) {
resetTimer();
}
}
启动、启动和重置Timer比较简单,直接使用Timer的Start和Stop就可以了.
publicvoid startTimer() {
TIMER.start();
}
重置的话还要停止Timer后再刷新一次画面.
再来就是Timer启动后触发的事件:
@Override
publicvoid actionPerformed(ActionEvent event) {
在这里会根据计数设置当前应该显示的图片,最后调用repaint.
if (sec_right == 10) {
sec_right = 0;
sec_left++;
}
最后就是复写paintComponent方法使组件更新了:
@Override
protectedvoid paintComponent(Graphics g) {
首先取得绘制的上下文Graphics2D g2 = (Graphics2D) g.create();
然后设置绘制的属性和样式:
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_PURE);
g2.setRenderingHint(RenderingHints.KEY_DITHERING,
RenderingHints.VALUE_DITHER_ENABLE);
g2.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
设置好颜色、锯齿、混合色、边等属性后就可以绘制了:
//背景的绘制
g2.drawImage(BACKGROUND_IMAGE, 0, 0, this);
//点的绘制
g2.drawImage(DOTS_ON, 172, 90, this);
//时分秒等的绘制
g2.drawImage(DIGIT_ARRAY[hour_left], 38, 90, this);
绘制完所有的时分秒、点之后,重写就完成了.
因为这个组件就是一个Panel,可以和正常Panel一样使用,通过new MissionTimerPanel();就可以调用了.