用java设计一个速度表盘_<JAVA图像学习笔记>关于Graphics/Graphics2D以及简单的几何图像制作(一个简单钟表的实现)...

题外话:正好赶上OperatingSystem的作业要做一个模拟线程/进程调度的问题,决定用JAVA实现才发现这些内容和之前学过的GUI制作是两码事儿- -b

通过学习java.swing库的ActionListener接口我们初步了解了一些关于java框体程序的各个部件JFrame,JPanel,JComponent和控件之间是如何联系通讯的,然而这次我们要从另一个视角来看java程序框体。

从一个框体实现“表”的代码我们来初步看一下java是如何在JFrame平台上制作出自己想要的图案的吧!

(实现效果图)

e674defd33726741c39e487709a80d23.png

有几个可能会比较陌生的类先筛选出来:

(1)GeneralPath:是java.awt.geom.Path2D的一个子类,path的设定过程主要用两个函数moveTo(double x,double y)和linkTo(double x,double y),当然如果需要实现path的动态绘制的话需要的方法远不止这两个,可以自行去javadoc查阅。

(2)Ellipse2D:是java.awt.geom下的一个类,可以用来绘制理论上的椭圆构造参数为(double x,double y,double width,double height)意义不多赘述。

(3)AffineTransform:这个是整个代码中最有分量的一个类,这个类的引用的获取方法是用静态方法AffineTransform.getInstance(double theta,double x,double y)这里的x和y指的是锚点也就是整个旋转过程参照的旋转中心,theta是要用弧度制表示的旋转角度。具体使用方法下文中会详细总结。

(4)Timer类是在我接触到的新的控件,和JButton或者JLabel等等不同的是这个空间不要手动加上ActionListener的接口来进行事件驱动。使用方法在代码中有详述。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 import java.awt.*;2 import java.awt.event.*;3 import java.awt.geom.*;4 importjava.util.Calendar;5 import javax.swing.*;6

7 public class Main extends JPanel implementsActionListener8 {9 //Create a shape for the face of the clock

10 protected static Ellipse2D face = new Ellipse2D.Float(3, 3, 94, 94);11

12 //Create a path that represents a tick mark

13 protected static GeneralPath tick = newGeneralPath();14 static

15 {16 tick.moveTo(100, 100);17 tick.moveTo(49, 0);18 tick.lineTo(51, 0);19 tick.lineTo(51, 6);20 tick.lineTo(49, 6);21 tick.lineTo(49, 0);22

23 }24

25 //Create a cool hour hand

26 protected static GeneralPath hourHand = newGeneralPath();27 static

28 {29 hourHand.moveTo(50, 15);30 hourHand.lineTo(53, 50);31 hourHand.lineTo(50, 53);32 hourHand.lineTo(47, 50);33 hourHand.lineTo(50, 15);34 }35

36 //Create a cool minute hand

37 protected static GeneralPath minuteHand = newGeneralPath();38 static

39 {40 minuteHand.moveTo(50, 2);41 minuteHand.lineTo(53, 50);42 minuteHand.lineTo(50, 58);43 minuteHand.lineTo(47, 50);44 minuteHand.lineTo(50, 2);45 }46

47 //And a cool second hand

48 protected static GeneralPath secondHand = newGeneralPath();49 static

50 {51 secondHand.moveTo(49, 5);52 secondHand.lineTo(51, 5);53 secondHand.lineTo(51, 62);54 secondHand.lineTo(49, 62);55 secondHand.lineTo(49, 5);56 }57

58 //Create some colors for the pieces of the clock

59 protected static Color faceColor = new Color(220, 220, 220);60 protected static Color hourColor =Color.red.darker();61 protected static Color minuteColor =Color.blue.darker();62 protected static Color secondColor = new Color(180, 180, 0);63 protected static Color pinColor =Color.gray.brighter();64

65 //Create circles for the pivot and center pin

66 protected Ellipse2D pivot = new Ellipse2D.Float(47, 47, 6, 6);67 protected Ellipse2D centerPin = new Ellipse2D.Float(49, 49, 2, 2);68

69

70 //Create three transforms that center around the pivot point

71 protected AffineTransform hourTransform =

72 AffineTransform.getRotateInstance(0, 50, 50);73 protected AffineTransform minuteTransform =

74 AffineTransform.getRotateInstance(0, 50, 50);75 protected AffineTransform secondTransform =

76 AffineTransform.getRotateInstance(0,50,50);77

78 //Create a timer that fires once a second and a Calendar79 //instance for getting the time values

80 protected Timer timer = new Timer(1000, this);81 protected Calendar calendar =Calendar.getInstance();82

83 //Constructor - hardcode a preferred size of 100x100

84 publicMain()85 {86 setPreferredSize(new Dimension(100, 100));87 }88

89 //Invoked when panel is added to a container

90 public voidaddNotify()91 {92 //Call the superclass and start the timer

93 super.addNotify();94 timer.start();95 }96

97 //Invoked when panel is removed from a container

98 public voidremoveNotify()99 {100 //Call the superclass and stop the timer

101 timer.stop();102 super.removeNotify();103 }104

105 //106 public voidactionPerformed(ActionEvent event)107 {108 //Update the calendar's time

109 this.calendar.setTime(newjava.util.Date());110

111 //Extract the hours minutes and seconds

112 int hours = this.calendar.get(Calendar.HOUR);113 int minutes = this.calendar.get(Calendar.MINUTE);114 int seconds = this.calendar.get(Calendar.SECOND);115

116 //Using a little trigonometry, set the transforms to rotate117 //each hand into the proper position. Center the rotation118 //around the pivot point (50, 50) instead of the origin

119 hourTransform.setToRotation(((double) hours) *

120 (Math.PI / 6.0), 50, 50);121 minuteTransform.setToRotation(((double) minutes) *

122 (Math.PI / 30.0), 50, 50);123 secondTransform.setToRotation(((double) seconds) *

124 (Math.PI / 30.0), 50, 50);125

126 //Force the component to repaint ASAP

127 repaint();128 }129

130 //This is an alternative to creating a UI delegate. Since JPanel's131 //paint() method only paints the border and backgound, we can just132 //override the paint method of the component to do the graphics.

133 public voidpaint(Graphics g)134 {135 //Call the superclass first to paint the border (if one is assigned)

136 super.paint(g);137

138 //Get the graphics context and turn on anti-aliasing

139 Graphics2D g2 =(Graphics2D) g;140 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,141 RenderingHints.VALUE_ANTIALIAS_ON);142

143 //Set the paint for the clock face and fill it in

144 g2.setPaint(faceColor);145 g2.fill(face);146

147 //Set the paint to black and draw the clock's outline

148 g2.setPaint(Color.black);149 g2.draw(face);150

151 //Fill in the 12 ticks around the face of the clock

152 for (double p = 0.0; p < 12.0; p += 1.0)153 {154 //This is probably terribly inefficient and should be155 //done statically or in the constructor - draw the156 //tick as a transformed shape that is rotated.

157 g2.fill(tick.createTransformedShape(158 AffineTransform.getRotateInstance((Math.PI / 6.0) *p,159 50, 50)));160 }161

162 //Set the paint and draw the hour hand. It is lowest in the163 //'z-order' so will appear underneath the other hands. Notice164 //how each hand is transformed by a different .

165 g2.setPaint(hourColor);166 g2.fill(hourHand.createTransformedShape(hourTransform));167

168 //Set the paint and draw the minute hand, the second hand,169 //the pivot and the center pin

170 g2.setPaint(minuteColor);171 g2.fill(minuteHand.createTransformedShape(minuteTransform));172 g2.setPaint(secondColor);173 g2.fill(secondHand.createTransformedShape(secondTransform));174 g2.fill(pivot);175 g2.setPaint(pinColor);176 g2.fill(centerPin);177 }178

179 //A little test frame to show off our fancy clock

180 public static voidmain(String[] args)181 {182 JFrame frame = newJFrame();183 frame.setLocation(700, 400);184 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);185 frame.getContentPane().add(newMain());186 frame.pack();187 frame.show();188 }189 }

View Code

Okay,Here are the points :-P

下面进阶深入探究一下这段代码:

#1#关于每次图形变换之后,变化前图形的擦除?

Ans:是这样的,一般来讲有两种办法实现所谓的擦除效果以完成动画:

1.手动擦除,直接对这个paint出来的geom下的类调用clear**方法,或者直接使用新的颜色/画布将需要擦除的形状删除/覆盖。

2.super.paint(g)这个方法有点神奇,以后需要进一步探讨一下,直接在子类的paint方法之中调用父类的paint的方法来实现“擦除”。

代码中方法其实是第一种,在每次repaint过程中,都会有一次将整个表盘“覆盖”重画的过程,但是不得不说,这么实现的话每秒钟都需要对整个表盘全部的空间进行重画,是很浪费时间/空间的。

#2#怎么递推实现的表盘圆周上的12个标记的绘制?

Ans:这里用了一个新的类叫做AffineTransform。使用这个类的方法是在geom下的几何类中直接调用createTransformedShape(AffineTransform at)返回一个Shape类型,这时匿名调用这个类进行draw(勾勒轮廓)/fill(填充颜色)方法可以完成对转换完成之后的几何体的绘制。关于AffineTransform类的更多用法和数学解释:

#3#怎么实现消除斜线的锯齿状?

Ans:这个我真的不懂,但是我知道是下面这段神奇的代码起到的作用,至于这个“渲染提示”具体的用法还得慢慢学..

g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);

#4#阿西巴,addNotify方法到底有没有用?

Ans:addNotify方法是在JPanel添加到JComponent上的时候用的,本例中是在添加pane的直接启动计时器(Timer),关于代码最后那个若有若无的getContentPane()为什么会出现,其实还要从JFrame的四层结构开始说起(传送门见下):

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值