import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.Calendar;
import javax.swing.*;
public class Clock2DPanel extends JPanel implements ActionListener {
// 创建时钟表面
// public abstract class Ellipse2D extends RectangularShape
// protected Ellipse2D() 不能直接实例化,可以通过子类来实例化
// public static class Ellipse2D.Float extends Ellipse2D
// Ellipse2D.Float(左上角坐标x,y,高,宽)
protected static Ellipse2D face = new Ellipse2D.Float(3, 3, 94, 94);
// Create a path that represents a tick mark
// 创建路径核对(嘀嗒)符号
protected static GeneralPath tick = new GeneralPath();
static {
// void moveTo(float x, float y)
// 通过移动到指定坐标实现增加一个点到路径
tick.moveTo(100, 100);
tick.moveTo(49, 0);
// 通过从当前坐标到新指定坐标绘制一条直线到路径中
tick.lineTo(51, 0);
tick.lineTo(51, 6);
tick.lineTo(49, 6);
tick.lineTo(49, 0);
}
// Create a cool hour hand
// 创建时手柄
protected static GeneralPath hourHand = new GeneralPath();
static {
hourHand.moveTo(50, 15);
hourHand.lineTo(53, 50);
hourHand.lineTo(50, 53);
hourHand.lineTo(47, 50);
hourHand.lineTo(50, 15);
}
// Create a cool minute hand
// 分手柄
protected static GeneralPath minuteHand = new GeneralPath();
static {
minuteHand.moveTo(50, 2);
minuteHand.lineTo(53, 50);
minuteHand.lineTo(50, 58);
minuteHand.lineTo(47, 50);
minuteHand.lineTo(50, 2);
}
// And a cool second hand
// 秒手柄
protected static GeneralPath secondHand = new GeneralPath();
static {
secondHand.moveTo(49, 5);
secondHand.lineTo(51, 5);
secondHand.lineTo(51, 62);
secondHand.lineTo(49, 62);
secondHand.lineTo(49, 5);
}
// Create some colors for the pieces of the clock
// 创建时钟块颜色
// Color 's Field :static Color red,blue,gray
// 域继承了 java.awt.Transparency 接口
// Color darker() : 创建当前颜色的发暗版本
protected static Color faceColor = new Color(220, 220, 220);
protected static Color hourColor = Color.red.darker();
protected static Color minuteColor = Color.blue.darker();
protected static Color secondColor = new Color(180, 180, 0);
protected static Color pinColor = Color.gray.brighter();
// Create circles for the pivot and center pin
// 创建作为枢轴的中心圆圈
protected Ellipse2D pivot = new Ellipse2D.Float(47, 47, 6, 6);
protected Ellipse2D centerPin = new Ellipse2D.Float(49, 49, 2, 2);
// Create three transforms that center around the pivot point
// 创建以枢轴点为中心的三个转换
// AffineTransform 仿射平移
// getRotateInstance(旋转弧度,定位点坐标)
// 返回一个定位点周围的旋转坐标的转换
protected AffineTransform hourTransform =
AffineTransform.getRotateInstance(0, 50, 50);
protected AffineTransform minuteTransform =
AffineTransform.getRotateInstance(0, 50, 50);
protected AffineTransform secondTransform =
AffineTransform.getRotateInstance(0, 50, 50);
// Create a timer that fires once a second and a Calendar
// instance for getting the time values
// 创建计时器,每秒运行一次
// 日历实例产生时间值
// java.util.Timer 开头并没有 import 但这里可以运行 ?!?!
// public Timer(boolean isDaemon) 创建作为精灵线程运行的关联线程
// api 中没有 Time(int,Object)的构造器?!?!
protected Timer timer = new Timer(1000, this);
protected Calendar calendar = Calendar.getInstance();
// Constructor - hardcode a preferred size of 100x100
// 创建首选尺寸 Dimension(宽, 高)
public Clock2DPanel() {
setPreferredSize(new Dimension(100, 100));
}
// Invoked when panel is added to a container
// 当这个时钟面板被添加到一个容器中
// 在本类父类层次中发现这个方法
// java.awt.Container : void addNotify()
// Makes this Container displayable by connecting it to
// a native screen resource.
// 通过连接他到本地屏幕资源中使他可显示
// 而 void removeNotify()
// Makes this Container undisplayable by removing its
// connection to its native screen resource.
// 通过删除连接使他不可显示
public void addNotify() {
// Call the superclass and start the timer
// 这里的 super 是父类层次,不是绝对父类
super.addNotify();
// Timer 计时器是个线程,具有 start,stop 方法
timer.start();
}
// Invoked when panel is removed from a container
// 当这个时钟面板从一个容器中删除
public void removeNotify() {
// Call the superclass and stop the timer
timer.stop();
super.removeNotify();
}
// 计时器动作事件
public void actionPerformed(ActionEvent event) {
// Update the calendar's time
// 取得日历时间
this.calendar.setTime(new java.util.Date());
// Extract the hours minutes and seconds
// public int get(int field) : field - the given time field
// Field Summary : static int HOUR,MINUTE,SECOND
// 分别取得日历中时分秒
int hours = this.calendar.get(Calendar.HOUR);
int minutes = this.calendar.get(Calendar.MINUTE);
int seconds = this.calendar.get(Calendar.SECOND);
// Using a little trigonometry, set the transforms to rotate
// each hand into the proper position. Center the rotation
// around the pivot point (50, 50) instead of the origin
// 以时针为例:
// 走满12格为 2 PI
// 所以转换弧度 = 当前时数/12格 * 2 PI = 当前时数 / 6 * PI
// 分针秒针均 60 格
hourTransform.setToRotation(((double) hours) *
(Math.PI / 6.0), 50, 50);
minuteTransform.setToRotation(((double) minutes) *
(Math.PI / 30.0), 50, 50);
secondTransform.setToRotation(((double) seconds) *
(Math.PI / 30.0), 50, 50);
// Force the component to repaint ASAP
repaint();
}
// This is an alternative to creating a UI delegate. Since JPanel's
// paint() method only paints the border and backgound, we can just
// override the paint method of the component to do the graphics.
public void paint(Graphics g) {
// Call the superclass first to paint the border (if one is assigned)
super.paint(g);
// Get the graphics context and turn on anti-aliasing
Graphics2D g2 = (Graphics2D) g;
// 开启反锯齿
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// Set the paint for the clock face and fill it in
// 时钟表面颜色设置和填充
g2.setPaint(faceColor);
g2.fill(face);
// Set the paint to black and draw the clock's outline
// 黑色绘画时钟轮廓
g2.setPaint(Color.black);
g2.draw(face);
// Fill in the 12 ticks around the face of the clock
// 填充 12 个嘀嗒记号
for (double p = 0.0; p < 12.0; p += 1.0) {
// This is probably terribly inefficient and should be
// done statically or in the constructor - draw the
// tick as a transformed shape that is rotated.
// Shape createTransformedShape(Shape pSrc)
// 创建由指定的形状转换后的新形状对象
g2.fill(tick.createTransformedShape(
// 获取转换对象
AffineTransform.getRotateInstance((Math.PI / 6.0) * p,
50, 50)));
}
// Set the paint and draw the hour hand. It is lowest in the
// 'z-order' so will appear underneath the other hands. Notice
// how each hand is transformed by a different .
// 绘画时针
g2.setPaint(hourColor);
g2.fill(hourHand.createTransformedShape(hourTransform));
// Set the paint and draw the minute hand, the second hand,
// the pivot and the center pin
// 绘画分针
g2.setPaint(minuteColor);
g2.fill(minuteHand.createTransformedShape(minuteTransform));
// 绘画秒针
g2.setPaint(secondColor);
g2.fill(secondHand.createTransformedShape(secondTransform));
// 绘画枢轴,与秒针同色
g2.fill(pivot);
g2.setPaint(pinColor);
// 绘画表面颜色
g2.fill(centerPin);
}
// A little test frame to show off our fancy clock
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setLocation(700, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new Clock2DPanel());
frame.pack();
frame.show();
}
}