哎,好久没上博客园发东西了,上一次还是两个月前的五一写的一篇计算器博客,不过意外的是那个程序成了这学期的Java大作业,所以后来稍微改了一下那个程序就交了上去,这还是美滋滋。然后五月中旬的时候写了一个2048小游戏,由于写完第二个版本第二天就生病了,休养了好几天才缓过来,最后嫌麻烦就没发园子里了,直接挂Github上了。然后又忙着准备期末,期末玩休息了5天又开始数据库课程设计,用Java写了一个小系统,花了一个星期左右,写了差不多3500行了。然后写完就放学了,放学的日子就感觉自己开始懒散了,静不下心来写东西,每天睡觉,看一些无聊的视频。。。前几天算是缓过神来,找回了脑子,于是又开始想着在放弃Java之前再多写一点东西,于是花了两个下午写了一个时钟,感觉看着还行。
-----------------------------------以下是正经话-----------------------------------
其实这个程序并不难,主要是用Java 2D画图,弄一个线程,每隔一秒,依照时针分针秒针各自的速度重新计算它们走过的角度(相对12点方向顺时针偏离的角度),利用这个角度算出它们各自端点的坐标,重绘一次表针,达到刷新的目的,最后时限走动的效果,思路很简单,清晰明了。但是关键是这个画图呀,想着很容易,重写继承过来的JFrame里的paint函数就行,最后发现效果并不是期待的那样,而是一闪一闪的,于是去寻找原因,结果,尼玛,原来水这么深,一下子触到了知识盲区,什么repaint的实现细节,先调用update,再调用paint,update函数又是如何工作的,慢慢弄懂了它为什么会一闪一闪的原因,然后寻找解决办法,然后就看到了什么双缓冲原理,WTF!什么玩意呀,根本没听过,然后乖乖地去看那东西的实现原理,又看到有人建议不要去重写paint方法,说是会遇到诸多意想不到的问题,建议去重写paintComponent方法,可是书本上画图的例子都是重写paint方法呀,况且我也没听过paintComponent,无奈,又去看了一下paint的工作原理,原来它会调用paintComponent,最后放弃了自己实现双缓冲,乖乖改用了paintComponent。。。
其实我还遇到了几个脑残的问题,比如在画秒针时,直接把画时针的部分代码复制下来,最后忘了改掉走动的速度,结果运行时还在想秒针怎么走不动呢?原谅我是个逗逼,还有什么秒针逆时针走动,最后才发现算坐标时误把y轴正方向当成了向上,哎。。。
Anyway,最后运行的效果还是挺好的
-----------------------------------以下是代码-----------------------------------
1 import java.awt.*; 2 import java.util.Date; 3 import javax.swing.*; 4 5 public class Clock extends JComponent{ 6 /** 7 * 8 */ 9 private static final long serialVersionUID = -5379472973578609775L; 10 private Font f = new Font("微软雅黑",Font.PLAIN,15); 11 private Font f2 = new Font("微软雅黑",Font.BOLD,15); 12 private JLabel l = new JLabel("当前时间:"); 13 private JLabel display = new JLabel(); 14 private JLabel display2 = new JLabel(""); 15 private int hour = 0; 16 private int min = 0; 17 private int sec = 0; 18 private Date now = new Date(); 19 private Graphics2D g; 20 final double PI = Math.PI; 21 private String strTime = "" ; 22 23 @SuppressWarnings("deprecation") 24 public Clock(){ 25 add(l); 26 l.setBounds(120, 320, 80, 20); 27 l.setFont(f); 28 add(display); 29 display.setBounds(195, 320, 80, 20); 30 display.setFont(f); 31 display.setBorder(BorderFactory.createLineBorder(Color.black)); 32 add(display2); 33 display2.setBounds(90, 350, 250, 20); 34 display2.setFont(f); 35 hour = now.getHours(); 36 min = now.getMinutes(); 37 sec = now.getSeconds(); 38 setVisible(true); 39 } 40 41 public void paintComponent(Graphics g1){ 42 double x,y; 43 super.paintComponent(g1); 44 g = (Graphics2D) g1; 45 //反锯齿开关开 46 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 47 48 //画表盘 49 g.setPaint(new GradientPaint(5,40,Color.blue,15,50,Color.yellow,true)); 50 g.setStroke( new BasicStroke(3,BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL)); 51 g.drawOval(75, 40, 250, 250); 52 g.fillOval(195, 160, 10, 10); 53 g.setColor(Color.black); 54 55 //画60个点 56 for(int i = 0;i < 60;i++) 57 { 58 double[] co = new double[2]; 59 co = paint_Dot(i * 2 * PI / 60); 60 x = co[0]; 61 y = co[1]; 62 if(i == 0 || i == 15 || i == 30 || i == 45)//画3,6,9,12四个大点 63 { 64 g.fillOval((int)(x - 5 + 200),(int)(y - 5 + 165),10,10); 65 } 66 else//其他小点 67 { 68 g.fillOval((int)(x - 2.5 + 200),(int)(y - 2.5 + 165),5,5); 69 } 70 } 71 72 //画四个数字 73 g.setFont(f2); 74 g.drawString("3", 300, 171); 75 g.drawString("6", 195, 273); 76 g.drawString("9", 91, 171); 77 g.drawString("12", 190, 68); 78 79 //画时针,分针,秒针 80 paint_HourPointer(hour*3600 + min*60 + sec,g);//时针走过的秒数 81 paint_MinutePointer(min*60 + sec,g);//分针走过的秒数 82 paint_SecondPointer(sec,g);//秒针走过的秒数 83 } 84 85 public void showUI(){ 86 new Thread() { 87 @SuppressWarnings("deprecation") 88 public void run() { 89 while (true) 90 { 91 now = new Date(); 92 hour = now.getHours(); 93 min = now.getMinutes(); 94 sec = now.getSeconds(); 95 try { 96 Thread.sleep(1000); 97 } catch (InterruptedException ex) { 98 ex.printStackTrace(); 99 } 100 showTime(); 101 repaint(); 102 } 103 } 104 }.start(); 105 } 106 107 public void paint_HourPointer(int second,Graphics2D g){//second表示当前时间的时针相对00:00:00走了多少秒 108 double x,y,angle; 109 angle = second * PI / 21600;//时针的速度为PI/21600 (rad/s) 110 x = 200 + 60 * Math.sin(angle); 111 y = 165 - 60 * Math.cos(angle); 112 g.setStroke( new BasicStroke(5,BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND)); 113 g.setPaint(new GradientPaint(200,165,Color.red,260,165,Color.blue,true)); 114 g.drawLine(200, 165, (int)x, (int)y); 115 } 116 117 public void paint_MinutePointer(int second,Graphics2D g){//second表示当前时间的分针相对00:00:00走了多少秒 118 double x,y,angle; 119 angle = second * PI / 1800;//分针的速度为PI/1800 (rad/s) 120 x = 200 + 80 * Math.sin(angle); 121 y = 165 - 80 * Math.cos(angle); 122 g.setStroke( new BasicStroke(3,BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND)); 123 g.setPaint(new GradientPaint(200,165,Color.magenta,280,165,Color.blue,true)); 124 g.drawLine(200, 165, (int)x, (int)y); 125 } 126 127 public void paint_SecondPointer(int second,Graphics2D g){//second表示当前时间的秒针相对00:00:00走了多少秒 128 double x,y,x1,y1,x2,y2,x3,y3,angle; 129 double cos = 90 / Math.sqrt(8125);//90*90+5*5 130 double sin = 5 / Math.sqrt(8125); 131 angle = second * PI / 30;//时针的速度为PI/30 (rad/s) 132 x = 200 + 95 * Math.sin(angle); 133 y = 165 - 95 * Math.cos(angle); 134 x1 = 200 + 20 * Math.sin(angle + PI); 135 y1 = 165 - 20 * Math.cos(angle + PI); 136 x2 = 200 + Math.sqrt(8125)* ( Math.sin(angle)*cos - Math.cos(angle)*sin ); //sin(a-b) 137 y2 = 165 - Math.sqrt(8125)* ( Math.cos(angle)*cos + Math.sin(angle)*sin ); //cos(a-b) 138 x3 = 200 + Math.sqrt(8125)* ( Math.sin(angle)*cos + Math.cos(angle)*sin ); //sin(a+b) 139 y3 = 165 - Math.sqrt(8125)* ( Math.cos(angle)*cos - Math.sin(angle)*sin ); //cos(a+b) 140 g.setStroke( new BasicStroke(2,BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL)); 141 g.setPaint(new GradientPaint(180,165,Color.CYAN,295,165,Color.MAGENTA,true)); 142 g.drawLine((int)x1, (int)y1, (int)x, (int)y); 143 g.drawLine((int)x2, (int)y2, (int)x, (int)y); 144 g.drawLine((int)x3, (int)y3, (int)x, (int)y); 145 } 146 147 public double[] paint_Dot(double angle){ 148 double[] co = new double[2]; 149 co[0] = 115 * Math.cos(angle);//横坐标 150 co[1] = 115 * Math.sin(angle);//纵坐标 151 return co; 152 } 153 154 @SuppressWarnings("deprecation") 155 private void showTime(){ 156 String date; 157 int hour_temp = hour,min_temp = min,sec_temp = sec; 158 sec_temp += 1 ; 159 if(sec_temp >= 60) 160 { 161 sec_temp = 0; 162 min_temp += 1 ; 163 } 164 if(min_temp>=60){ 165 min_temp=0; 166 hour_temp+=1; 167 } 168 if(hour_temp < 10) 169 strTime = "0" + hour_temp + ":"; 170 else 171 strTime = "" + hour_temp + ":"; 172 173 if(min_temp < 10) 174 strTime = strTime + "0" + min_temp + ":"; 175 else 176 strTime = strTime + "" + min_temp + ":"; 177 178 if(sec < 10) 179 strTime = strTime + "0" + sec_temp; 180 else 181 strTime = strTime + "" + sec_temp; 182 //在窗体上设置显示时间 183 date = " " + (now.getYear()+1900) + "年" + (now.getMonth()+1) + "月" + now.getDate() + "日 " + "星期" ; 184 switch (now.getDay()) { 185 case 1: 186 date += "一"; 187 break; 188 case 2: 189 date += "二"; 190 break; 191 case 3: 192 date += "三"; 193 break; 194 case 4: 195 date += "四"; 196 break; 197 case 5: 198 date += "五"; 199 break; 200 case 6: 201 date += "六"; 202 break; 203 case 7: 204 date += "日"; 205 break; 206 } 207 date += " CST"; 208 strTime = " " + strTime; 209 display.setText(strTime); 210 display2.setText(date); 211 } 212 213 public static void main(String args[]){ 214 Clock c = new Clock(); 215 c.showUI(); 216 JFrame f = new JFrame("Clock By XJX"); 217 Image img=Toolkit.getDefaultToolkit().getImage("title.gif");//窗口图标 218 f.setIconImage(img); 219 f.setSize(400,400); 220 f.setResizable(false); 221 f.add(c, BorderLayout.CENTER); 222 f.setLocationRelativeTo(null); 223 f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 224 f.setVisible(true); 225 } 226 }