1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
|
// File : GUI-lowlevel/animation/analogclock/Clock.java
// Purpose: An analog clock component -- Uses Timer and Calendar.
// Note : Uses a BufferedImage for clock face so isn't drawn each time.
// Author : Fred Swartz, 1999-2007, Placed in public domain.
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.image.*;
//////////////////////////////////////////////////////////////// Clock class
class Clock extends JComponent {
//============================================================ constants
private static final double TWO_PI = 2.0 * Math.PI;
private static final int UPDATE_INTERVAL = 100; // Millisecs
//=============================================================== fields
private Calendar _now = Calendar.getInstance(); // Current time.
private int _diameter; // Height and width of clock face
private int _centerX; // x coord of middle of clock
private int _centerY; // y coord of middle of clock
private BufferedImage _clockImage; // Saved image of the clock face.
private javax.swing.Timer _timer; // Fires to update clock.
//==================================================== Clock constructor
public Clock() {
setPreferredSize(new Dimension(300,300));
_timer = new javax.swing.Timer(UPDATE_INTERVAL, new ActionListener() {
public void actionPerformed(ActionEvent e) {
updateTime();
repaint();
}
});
}
//================================================================ start
/** Start the timer. */
public void start() {
_timer.start();
}
//================================================================= stop
/** Stop the timer. */
public void stop() {
_timer.stop();
}
//=========================================================== updateTime
private void updateTime() {
//... Avoid creating new objects.
_now.setTimeInMillis(System.currentTimeMillis());
}
//======================================================= paintComponent
@Override public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
//... The panel may have been resized, get current dimensions
int w = getWidth();
int h = getHeight();
_diameter = ((w < h) ? w : h);
_centerX = _diameter / 2;
_centerY = _diameter / 2;
//... Create the clock face background image if this is the first time,
// or if the size of the panel has changed
if (_clockImage == null
|| _clockImage.getWidth() != w
|| _clockImage.getHeight() != h) {
_clockImage = (BufferedImage)(this.createImage(w, h));
//... Get a graphics context from this image
Graphics2D g2a = _clockImage.createGraphics();
g2a.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
drawClockFace(g2a);
}
//... Draw the clock face from the precomputed image
g2.drawImage(_clockImage, null, 0, 0);
//... Draw the clock hands dynamically each time.
drawClockHands(g2);
}
//====================================== convenience method drawClockHands
private void drawClockHands(Graphics2D g2) {
//... Get the various time elements from the Calendar object.
int hours = _now.get(Calendar.HOUR);
int minutes = _now.get(Calendar.MINUTE);
int seconds = _now.get(Calendar.SECOND);
int millis = _now.get(Calendar.MILLISECOND);
//... second hand
int handMin = _diameter / 8; // Second hand doesn't start in middle.
int handMax = _diameter / 2; // Second hand extends to outer rim.
double fseconds = (seconds + (double)millis/1000) / 60.0;
drawRadius(g2, fseconds, 0, handMax);
//... minute hand
handMin = 0; // Minute hand starts in middle.
handMax = _diameter / 3;
double fminutes = (minutes + fseconds) / 60.0;
drawRadius(g2, fminutes, 0, handMax);
//... hour hand
handMin = 0;
handMax = _diameter / 4;
drawRadius(g2, (hours + fminutes) / 12.0, 0, handMax);
}
//======================================= convenience method drawClockFace
private void drawClockFace(Graphics2D g2) {
// ... Draw the clock face. Probably into a buffer.
g2.setColor(Color.PINK);
g2.fillOval(0, 0, _diameter, _diameter);
g2.setColor(Color.BLACK);
g2.drawOval(0, 0, _diameter, _diameter);
int radius = _diameter / 2;
//... Draw the tick marks around the circumference.
for (int sec = 0; sec < 60; sec++) {
int tickStart;
if (sec%5 == 0) {
tickStart = radius - 10; // Draw long tick mark every 5.
} else {
tickStart = radius - 5; // Short tick mark.
}
drawRadius(g2, sec / 60.0, tickStart , radius);
}
}
//==================================== convenience method drawRadius
// This draw lines along a radius from the clock face center.
// By changing the parameters, it can be used to draw tick marks,
// as well as the hands.
private void drawRadius(Graphics2D g2, double percent,
int minRadius, int maxRadius) {
//... percent parameter is the fraction (0.0 - 1.0) of the way
// clockwise from 12. Because the Graphics2D methods use radians
// counterclockwise from 3, a little conversion is necessary.
// It took a little experimentation to get this right.
double radians = (0.5 - percent) * TWO_PI;
double sine = Math.sin(radians);
double cosine = Math.cos(radians);
int dxmin = _centerX + (int)(minRadius * sine);
int dymin = _centerY + (int)(minRadius * cosine);
int dxmax = _centerX + (int)(maxRadius * sine);
int dymax = _centerY + (int)(maxRadius * cosine);
g2.drawLine(dxmin, dymin, dxmax, dymax);
}
}
|