• <JAVA图像学习笔记>关于Graphics/Graphics2D以及简单的几何图像制作(一个简单钟表的实现)


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

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

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

      (实现效果图)


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

    (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的接口来进行事件驱动。使用方法在代码中有详述。

      1 import java.awt.*;
      2 import java.awt.event.*;
      3 import java.awt.geom.*;
      4 import java.util.Calendar;
      5 import javax.swing.*;
      6 
      7 public class Main extends JPanel implements ActionListener
      8 {
      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 = new GeneralPath();
     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 = new GeneralPath();
     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 = new GeneralPath();
     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 = new GeneralPath();
     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 Calendar
     79     // 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     public Main()
     85     {
     86         setPreferredSize(new Dimension(100, 100));
     87     }
     88 
     89     // Invoked when panel is added to a container
     90     public void addNotify()
     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 void removeNotify()
     99     {
    100 // Call the superclass and stop the timer
    101         timer.stop();
    102         super.removeNotify();
    103     }
    104 
    105     //
    106     public void actionPerformed(ActionEvent event)
    107     {
    108         // Update the calendar's time
    109         this.calendar.setTime(new java.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 rotate
    117         // each hand into the proper position.  Center the rotation
    118         // 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's
    131     // paint() method only paints the border and backgound, we can just
    132     // override the paint method of the component to do the graphics.
    133     public void paint(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 be
    155             // done statically or in the constructor - draw the
    156             // 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 the
    163         // 'z-order' so will appear underneath the other hands.  Notice
    164         // how each hand is transformed by a different <AffineTransform>.
    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 void main(String[] args)
    181     {
    182         JFrame frame = new JFrame();
    183         frame.setLocation(700, 400);
    184         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    185         frame.getContentPane().add(new Main());
    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类的更多用法和数学解释:

    http://www.apihome.cn/api/java/AffineTransform.html

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

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

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

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

    http://tieba.baidu.com/p/2004216123

  • 相关阅读:
    hadoop集群单点配置
    CentOS6.x环境通过yum命令在线安装或重装zookeeper-server
    层层递进——宽度优先搜索(BFS)
    解救小哈——DFS算法举例
    浅谈深度优先搜索
    CodeCombat森林关卡Python代码
    用OpenGL进行曲线、曲面的绘制
    CodeCombat地牢关卡Python代码
    转载:程序员都应该访问的最佳网站
    用OpenGL实现动态的立体时钟
  • 原文地址:https://www.cnblogs.com/guguli/p/4396686.html
Copyright © 2020-2023  润新知