Java:Java2D高级绘图

Java 2D高级绘图

知识要点: 

第一节  Java 2D的增强功能 

概述、AWT图形能力的不足、Java 2D API 

第二节  图形绘制的基本方法 

转换Graphics2D对象、Graphics 类特性、绘图的属性和基本编程方法 

第三节  曲线问题的高级应用开发 

直线问题深入研究、贝塞尔(Bezier)曲线、自定义样条曲线编程、 

用户数据的曲线显示、曲线用Applet显示的数据来源问题 

第四节  字符串的高级处理 

TextLayout类、LineMetrics类 

第五节  构造几何形状 

2D几何形状的设计、构造型区域几何形状、变换、缓冲的图像 

第六节  三维图形处理的设计技术 

透视投影、透视图形的显示、隐蔽面消除问题 

第七节  同环境交互 

GraphicsEnvironment类、GraphicsDevice类、GraphicsConfiguration类 













































第一节  Java 2D的增强功能 



一、概述: 



由Sun公司与Adobe系统公司合作推出的Java 2D API,提供了一个功能强大而且非常灵活的二维图形框架。Java 2D API扩展了java.awt包中定义的Graphics类和Image类,提供了高性能的二维图形、图像和文字,同时又维持了对现有AWT应用的兼容。 



二、AWT图形能力的不足: 



在 AWT 的初始实现中,图形能力并不十分完善。因为开发 JDK 是打算将其作为平台中立的实现平台,所以其原始的功能被限制于“最少公共功能”上,所有被支持的操作系统上保证提供这些公共功能; 

在 Java 2D 出现之前,对绘制能力、字体操作和图像控制的支持非常少。而对诸如用图案进行着色、形状操作以及图形变换之类的重要操作的支持则完全没有。 

Java 2D 满足了跨平台实现中对这些功能以及其它功能的需求。 



三、Java 2D API: 



它是JFC (Java Fundation Classes)的一员,加强了传统AWT( Abstract Windowing Toolkit )的描绘功能。在 JDK1.2中已经支援 Java 2D的使用。透过Java 2D API ,程序员可以轻松地描绘出任意的几何图形、运用不同的填色效果、对图形做旋转( rotate)、缩放( scale)、扭曲( shear)等。如图所示,程序员透过2D API所提供的功能,简单地利用不同类型的线或是填色效果绘出统计图,以区分出不同的资料。 

它们是基于Graphics2D类的绘图功能,是对AWT中的Graphics类的进一步的扩展和增强。主要体现在: 



1。对渲染质量的控制:消除锯齿以平滑绘制对象的边缘 

2.裁剪、合成和透明度:它们允许使用任意形状来限定绘制操作的边界。它们还提供对图形进行分层以及控制透明度和不透明度的能力。 

3.控制和填充简单及复杂的形状:这种功能提供了一个 Stroke 代理和一个 Paint 代理,前者定义用来绘制形状轮廓的笔(定义绘制的笔的宽度和样式),后者允许用纯色、渐变色和图案来填充形状。 

4。图像处理和变换:Java 2D 同 Java 高级图像API(Java Advanced Imaging API (JAI))协作,支持用大量图形格式处理复杂的图像。Java2D 还为您提供了修改图像、形状和字体字符的变换能力。 

5。特殊的填充方式,如梯度或者图案 

6.高级字体处理和字符串格式化:允许象操作任何其它图形形状一样操作字体字符。除此以外,可以象文字处理程序一样,通过为 String 中的字符应用属性和样式信息来创建格式化文本。 




java.awt.geom 包中的Areas类支援联集( union)、交集( intersection)、差集(subtraction )、Exclusive OR (XOR)等布尔运算。最後, AffineTransform 类别则提供图形物件做Scale(比例)、Shear(剪裁)、Rotate(旋转)等座标上的转换。 










第二节  图形绘制的基本方法 



一、转换Graphics2D对象 

   

绘制图形时,可以在Graphics对象或者Graphics2D对象上进行,它们都代表了需要绘图的区域,选择那个取决于是否要使用所增加的Java2D的图形功能。但要注意的是,所有的Java2D图形操作都必须在Graphics2D对象上调用。Graphics2D是Graphics的子类,同样包含在java.awt包中。 

public void paintComponent(Graphics comp) 

{     Graphics2D comp2D=(Graphics2D)comp; 



或者 

public void paint (Graphics comp) 

{     Graphics2D comp2D=(Graphics2D)comp; 







二、Graphics 类特性 



Graphics 类支持几种确定图形环境状态的特性。以下列出了部分特性: 

1)Color:当前绘制颜色,它属于 java.awt.Color 类型。所有的绘制、着色和纯文本输出都将以指定的颜色显示。 

2)Font:当前字体,它属于 java.awt.Font 类型。它是将用于所有纯文本输出的字体。 

3)Clip:java.awt.Shape 类型的对象,它充当用来定义几何形状的接口。该特性包含的形状定义了图形环境的区域,绘制将作用于该区域。通常情况下,这一形状与整个图形环境相同,但也并不一定如此。 

4)ClipBounds:java.awt.Rectangle 对象,它表示将包围由 Clip 特性定义的 Shape 的最小矩形。它是只读特性。 

5)FontMetrics:java.awt.FontMetrics 类型的只读特性。该对象含有关于图形环境中当前起作用的 Font 的信息。如同我们将看到的那样,获取此信息的这种机制已被 LineMetrics 类所取代 

6)Paint Mode:该特性控制环境使用当前颜色的方式。如果调用了 setPaintMode() 方法,那么所有绘制操作都将使用当前颜色。如果调用了 setXORMode() 方法(该方法获取一个 Color 类型的参数),那么就用指定的颜色对像素做“XOR”操作。XOR 具有在重新绘制时恢复初始位模式的特性,因此它被用作橡皮擦除和动画操作。 



三、绘图的属性和基本编程方法 



1)颜色Color类:没有变化。 

2)填充方式: 



Paint(油漆桶)接口有几个具体的实现,它们允许用纯色、渐变色或图案来填充形状。 



1,纯色填充(Color类):对 java.awt.Color 类做了一些调整以实现 Paint,并且可以用于纯色填充。 

2,渐变色来填充(梯度填充GradientPaint类):java.awt.GradientPaint 类允许用线性颜色渐变色来填充形状,线性颜色渐变色允许在两个指定的 Color 对象之间创建过渡。可以将渐变色设置成“周期性的”,这将导致渐变色图案重复出现。 

3,图案填充(纹理TexturePaint类):提供了 java.awt.TexturePaint 类,它可以用由 BufferedImage描述的图案填充形状 

编程方法: 

使用Graphics2D类中的setPaint()方法并使用Paint对象作为其参数,但由于任何可以作为填充的类如GradientPaint、TexturePaint和Color都实现了Paint接口(该接口注意定义了在Graphics2D下的颜色填充方式),因此可以将它们作为参数。如: 

public void paintComponent(Graphics comp) 

{     Graphics2D comp2D=(Graphics2D)comp; 

GradientPaint pat=newGradientPaint(0f,0f,Color.white,100f,45f,Color.blue); 

comp2D.setPaint(pat); 





3)设置笔的形状: 



Stroke 接口由 java.awt.BasicStroke 类实现。该类允许进行大量的选择以修改线的绘制细节。可以编程指定 BasicStroke 宽度,也可以指定对名为柱头和交点的路径上端点和交点的“装饰”。现在也可以绘制点划线了,只须设置 BasicStroke 的破折号属性即可。 

在Graphics类中线条是一个点宽,而在Graphics2D中可以通过BasicStoke类中的setStroke()方法来设置。其构造函数是BasicStroke(float width, int cap, int join) 

其中width指示线宽(缺省时为1.0) 

cap指示线的末端(包头,在BasicStroke类中定义出三个static 类型的常量如CAP_BUTT没有包头()、CAP_ROUND圆包头()、CAP_SQUARE方包头()的样式 



join指示线段之间的拐角(在BasicStroke类中定义出三个static 类型的常量如JOIN_BEVEL()、JOIN_MITER()、   JOIN_ROUND()样式。 



4)编程方法: 



public void paintComponent(Graphics comp) 

{     Graphics2D comp2D=(Graphics2D)comp; 



BasicStroke pen 

=new BasicStroke(2.0f, BasicStroke .CAP_BUTT, BasicStroke .JOIN_ROUND); 

comp2D.setStroke (pen); 





代码示例: 



       float thick =0.5f;         //设置画刷的粗细为0.5 

BufferedImage bi = new BufferedImage(800, 600,BufferedImage.TYPE_INT_RGB); 

Graphics2D g = (Graphics2D)bi.getGraphics(); 

Stroke stroke =g.getStroke();            //得到当前的画刷 

g.setStroke(new BasicStroke(thick, BasicStroke.CAP_SQUARE,BasicStroke.JOIN_ROUND)); 

g.draw(new Line2D.Float(x1, y1, x2, y2)); 画线 

g.setStroke( stroke ); //将画刷复原 





5)创建要绘制的形状对象 

   

在Java2D中进行绘图时,不是采用对应的方法来实现,而是为要实现某中形状创建出相应的形状对象。这可以通过使用java.awt.geom包中的类来定义所要创建的形状。如线条Line2D.Float类、距形Rectangle2D.Float或者Rectangle2D.Double类、椭圆Ellipes2D.Float、圆弧Arc2D.Float类等。 



6)绘制对象: 



1,可以使用Graphics2D类中的方法draw()用于绘制轮廓,而fill()方法用于填充。它们都以前面所创建的图形对象作为参数。 

2,Java2D中的字符串的绘制仍然采用drawString()方法,但有drawString(String s, float x, float y)和drawString(Stringstr, int x, int y)。 

3,绘制轮廓:draw(Shape s)其中的Shape接口在Graphics2D中被定义 

新的 Java 2D Shape 类都有“2D”后缀。这些新的形状使用浮点值(而不是整数)来描述其几何形状。 

Polygon类(int[] xpoints, int[] ypoints, int npoints) 

RectangularShape(抽象类,其子类有Arc2D, Ellipse2D, Rectangle2D, RoundRectangle2D), Rectangle(距形) 

QuadCurve2D(二次贝塞尔样条曲线,贝塞尔曲线由两个端点以及一个或两个控制点指定。贝塞尔曲线创建了适合于大多数表示的曲线。) 

CubicCurve2D(三次贝塞尔样条曲线) 

Area(区域) 

GeneralPath(由直线、二次样条曲线、三次样条曲线所构成) 

Line2D 



8)基本步骤 



绘图的第一个步骤是产生 Graphics2D 对象。然后设定所要的状态属性。例如你想要对一物件做渐层式的填色,可以设定属性 Paint为 GradientPaint。最後再调用Graphics2D所提供的方法fill或是draw,完成整个绘图的程序。 


9)程序实例 



例一: 

这是一个最简单的例子,也可以认为是绘图的一个最简单的框架。 



import java.awt.*; 

import java.awt.event.*; 

import javax.swing.*; 

import java.awt.geom.*; 

public class Map extends JFrame 

{   public Map() 

       {  super("Map"); 

         setSize(350,350); 

         MapPane map=newMapPane(); 

        getContentPane().add(map); 

       } 

       public static void main(String []arg) 

       {  Map frame=new Map(); 

          frame.show(); 

       } 



class MapPane extends JPanel 

{   public void paintComponent(Graphics comp) 

    {     Graphics2Dcomp2D=(Graphics2D)comp; 

      comp2D.drawString("sbcd",200,200); 

             Line2D.Float line=new Line2D.Float(1.0f,2.0f,200.0f,200.0f); 

       comp2D.draw(line); 

    } 









例二: 

下面是在Graphics2D模式下的基本绘图框架。我们可以看到,利用: 

        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 

                         RenderingHints.VALUE_ANTIALIAS_ON); 

通过该方法的设置,使图形去除锯齿状,可以得到多么细腻的图形。 



样例: 



import java.awt.*; 

import java.awt.event.*; 

import java.awt.geom.*; 



public class DrawDemo extends JFrame { 



  public DrawDemo(){ 

    //设置窗口的大小、标题 

    this.setSize(new Dimension(600, 400)); 

    

    //创建绘制各种形状的容器 

    ShapesPanel shapesPanel = new ShapesPanel(); 

    //将该容器加入窗口 

    getContentPane().add(shapesPanel,BorderLayout.CENTER); 

  } 



  public static void main(String[] args) { 

    DrawDemo frame = new DrawDemo(); 

    frame.setVisible(true); 

    //当窗口关闭时清空内存 

    frame.addWindowListener(new WindowAdapter() { 

        public voidwindowClosing(WindowEvent e) { 

           System.exit(0); 

        } 

    }); 

  } 





//创建各种容器的类 

class ShapesPanel extends JPanel { 

    final int maxCharHeight = 15; 

    final Color bg = Color.white; //声明背景颜色为灰色 

    final Color fg = Color.blue;     //声明前景颜色为蓝色 



    public ShapesPanel() { 

       setBackground(bg);           //设置背景颜色 

       setForeground(fg);           //设置前景颜色 

        //创建组合边框 

       setBorder(BorderFactory.createCompoundBorder( 

               BorderFactory.createRaisedBevelBorder(), 

               BorderFactory.createLoweredBevelBorder())); 

    } 





    public void paintComponent(Graphics g1) { 

       super.paintComponent(g1);      //清空背景颜色 





         float thick =0.5f;              //设置画刷的粗细为 0.5 

         Graphics2D g =(Graphics2D)g1; 

         Stroke stroke =g.getStroke();           //得到当前的画刷 

         g.setStroke(newBasicStroke(thick, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); 

         

         //通过该方法使图形去除锯齿状 

        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 

                         RenderingHints.VALUE_ANTIALIAS_ON); 

        

         

         String txt= "我的文章"; 

         

         int style=2;//0普通1粗体2斜体3粗斜 

         g.setFont(new Font("宋体", 2,15)); //15为字大小 

         //设置笔刷为黑色 

         g.setPaint(Color.black); 

         

         g.drawString(txt,200,150); 

         

         g.setPaint(Color.red); 

         g.draw(newLine2D.Float(0,0,200,150)); //画线 

         

         g.setPaint(Color.blue); 

         

         g.draw(newRectangle2D.Float(200,150,100,100)); 

         

         g.setStroke(stroke); //将画刷复原 

         

    } 









    例三:图形灵活的显示 

    

在上面的例子中,是使用一个继承于JPanel的类,覆盖它的void paintComponent(Graphics g1)事件方法,实现绘图的,这样虽然方便,但显得灵活性不高。 

实际上,通过JPanel对象直接赋值给Graphics2D对象,往往可以使程序具有很大的灵活性。程序可以这样来写。 



JPanel contentPane= (JPanel) this.getContentPane(); 

public Graphics2D comp2D=(Graphics2D)contentPane .getGraphics(); 



样例: 



package myDrawDemo; 



import java.awt.*; 

import java.awt.event.*; 

import javax.swing.*; 

import java.awt.geom.*; 



public class DrawDemo1 extends JFrame 



  public JPanel contentPane; //绘图窗口 

  public Graphics2D comp2D;    //绘图对象 

  JPanel jPanel1 = new JPanel();//控件容器 

  JButton jButton1 = new JButton(); 

  JButton jButton2 = new JButton(); 





  //构造函数 

  public DrawDemo1() { 

    enableEvents(AWTEvent.WINDOW_EVENT_MASK); 

    try { 

      jbInit(); 

    } 

    catch(Exception e) { 

      e.printStackTrace(); 

    } 

  } 



  //控件的初始化 



  private void jbInit() throws Exception  { 

    contentPane = (JPanel) this.getContentPane(); 

    contentPane.setLayout(new BorderLayout()); 

    this.setSize(new Dimension(400, 300)); 

    this.setTitle("Frame Title"); 

    //contentPane.setSize(400,240); 

    jPanel1.setLayout(null); 

    jButton1.setBounds(new Rectangle(30, 235, 100, 31)); 

    jButton1.setText("画线保留"); 



    jButton1.addActionListener(newjava.awt.event.ActionListener() { 

      public void actionPerformed(ActionEvent e){ 

        jButton1_actionPerformed(e); 

      } 

    }); 



    jButton2.setBounds(new Rectangle(150, 235, 100, 30)); 

    jButton2.setText("画线删除"); 

   

    jButton2.addActionListener(newjava.awt.event.ActionListener() { 

      public void actionPerformed(ActionEvent e){ 

        jButton2_actionPerformed(e); 

      } 

    }); 



     contentPane.add(jPanel1, BorderLayout.CENTER); 

    jPanel1.add(jButton1, null); 

    jPanel1.add(jButton2, null); 

  } 



   public static void main(String[] args) { 

    

    DrawDemo1 frame=new DrawDemo1(); 

    frame.show(); 

    frame.comp2D=(Graphics2D)frame.contentPane.getGraphics(); 

    frame.comp2D.setBackground(Color.white); 

    frame.comp2D.clearRect(0,0,401,221); 





  //Overridden so we can exit when window is closed 

  protected void processWindowEvent(WindowEvent e) { 

    super.processWindowEvent(e); 

    if (e.getID() == WindowEvent.WINDOW_CLOSING) { 

      System.exit(0); 

    } 

  } 



  void jButton1_actionPerformed(ActionEvent e){ 



       comp2D.setPaint(Color.red); 

       Line2D.Float line=new Line2D.Float(1.0f,2.0f,200.0f,220.0f); 

       comp2D.draw(line); 



  } 



  void jButton2_actionPerformed(ActionEvent e) { 

      

    comp2D.clearRect(0,0,401,221); 

    comp2D.setPaint(Color.blue); 

    Line2D.Float line=new Line2D.Float(1.0f,100.0f,300.0f,220.0f); 

    comp2D.draw(line); 

  } 









例四:剪裁 



图形处理问题中,剪裁由的时候是非常难处理的,所谓剪裁是指超过绘图取得内容不显示,看起来这是个简单问题,但由于所有的线条必须计算与边界的交点,而且边界有四个方向,这就使问题变得很复杂。java 2D很好的解决了这个问题,请看下面的例子。 



package myDrawDemo; 



import java.awt.*; 

import java.awt.event.*; 

import javax.swing.*; 

import java.awt.geom.*; 



public class DrawDemo2 extends JFrame 



  public JPanel contentPane; //绘图窗口 

  public Graphics2D comp2D;    //绘图对象 

  JPanel jPanel1 = new JPanel();//控件容器 

  JButton jButton1 = new JButton(); 

  JButton jButton2 = new JButton(); 





  //构造函数 

  public DrawDemo2() { 

    enableEvents(AWTEvent.WINDOW_EVENT_MASK); 

    try { 

      jbInit(); 

    } 

    catch(Exception e) { 

      e.printStackTrace(); 

    } 

  } 



  //控件初始化 



    private void jbInit() throws Exception  { 

    contentPane = (JPanel) this.getContentPane(); 

    contentPane.setLayout(new BorderLayout()); 

    this.setSize(new Dimension(400, 300)); 

    this.setTitle("Frame Title"); 

    //contentPane.setSize(400,240); 

    jPanel1.setLayout(null); 

    jButton1.setBounds(new Rectangle(30, 235, 100, 31)); 

    jButton1.setText("画线保留"); 



    jButton1.addActionListener(newjava.awt.event.ActionListener() { 

      public void actionPerformed(ActionEvent e){ 

        jButton1_actionPerformed(e); 

      } 

    }); 



    jButton2.setBounds(new Rectangle(150, 235, 100, 30)); 

    jButton2.setText("画线删除"); 

   

    jButton2.addActionListener(newjava.awt.event.ActionListener() { 

      public void actionPerformed(ActionEvent e){ 

        jButton2_actionPerformed(e); 

      } 

    }); 

   

     contentPane.add(jPanel1, BorderLayout.CENTER); 

    jPanel1.add(jButton1, null); 

    jPanel1.add(jButton2, null); 



  } 



   public static void main(String[] args) { 

    

    DrawDemo2 frame=new DrawDemo2(); 

    frame.show(); 

    frame.comp2D=(Graphics2D)frame.contentPane.getGraphics(); 

    frame.comp2D.setBackground(Color.white); 

    frame.comp2D.clearRect(0,0,401,221); 

   } 



  //Overridden so we can exit when window is closed 

  protected void processWindowEvent(WindowEvent e) { 

    super.processWindowEvent(e); 

    if (e.getID() == WindowEvent.WINDOW_CLOSING) { 

      System.exit(0); 

    } 

  } 



  void jButton1_actionPerformed(ActionEvent e){ 



       comp2D.setPaint(Color.red); 

       Line2D.Float line=newLine2D.Float(1.0f,2.0f,200.0f,220.0f); 





        comp2D.draw(line); 

  } 



  void jButton2_actionPerformed(ActionEvent e) { 

      

    comp2D.clearRect(0,0,401,221); 

    //剪裁 

    comp2D.setClip(50,50,300,150); 

    comp2D.setPaint(Color.blue); 

    Line2D.Float line=newLine2D.Float(1.0f,100.0f,300.0f,220.0f); 

    comp2D.draw(line); 

  } 





  





第三节  曲线问题的高级应用开发 



在jdk尚未支援 2D图形之前,只可以画出直的、相同粗细的线条。现在可以通过2D API绘出不同粗细的线条及圆滑的曲线。在java.awt.geom包中提供了Line2D、 QuadCurve2D(二次贝塞尔曲线)及 CubicCurve2D(三次贝塞尔曲线)等相关的类,让程序员能够轻松地绘出想要的线条。 

其实绘图的核心是画线,下面通过一些实例对一些问题进行深入的讨论。 



    一、直线问题深入研究 



样例: 

我们通过一个例子,深入的研究一下绘制直线和折线需要掌握哪些内容。 



package myDrawDemo; 



import java.awt.*; 

import java.awt.event.*; 

import javax.swing.*; 

import java.awt.geom.*; 



public class DrawDemo1 extends JFrame 



  public JPanel contentPane; //绘图窗口 

  public Graphics2D comp2D;    //绘图对象 

  JPanel jPanel1 = new JPanel();//控件容器 

  JButton jButton1 = new JButton(); 

  JButton jButton2 = new JButton(); 

  JButton jButton3 = new JButton(); 



  //构造函数 

  public DrawDemo1() { 

    enableEvents(AWTEvent.WINDOW_EVENT_MASK); 

    try { 

      jbInit(); 

    } 

    catch(Exception e) { 

      e.printStackTrace(); 

    } 

  } 



  //控件初始化 

  private void jbInit() throws Exception  { 

    contentPane = (JPanel) this.getContentPane(); 

    contentPane.setLayout(new BorderLayout()); 

    this.setSize(new Dimension(400, 300)); 

    this.setTitle("Frame Title"); 

    //contentPane.setSize(400,240); 

    jPanel1.setLayout(null); 

    jButton1.setBounds(new Rectangle(30, 235, 100, 31)); 

    jButton1.setText("园头"); 



    jButton1.addActionListener(new java.awt.event.ActionListener(){ 

      public void actionPerformed(ActionEvent e){ 

        jButton1_actionPerformed(e); 

      } 

    }); 



    jButton2.setBounds(new Rectangle(150, 235, 100, 30)); 

    jButton2.setText("方头"); 

   

    jButton2.addActionListener(newjava.awt.event.ActionListener() { 

      public void actionPerformed(ActionEvent e){ 

        jButton2_actionPerformed(e); 

      } 

    }); 



   jButton3.setBounds(new Rectangle(270, 235, 100, 30)); 

    jButton3.setText("封闭"); 

   

    jButton3.addActionListener(newjava.awt.event.ActionListener() { 

      public void actionPerformed(ActionEvent e){ 

        jButton3_actionPerformed(e); 

      } 

    }); 



     contentPane.add(jPanel1, BorderLayout.CENTER); 

    jPanel1.add(jButton1, null); 

    jPanel1.add(jButton2, null); 

    jPanel1.add(jButton3, null); 

  } 



   public static void main(String[] args) { 

    

    DrawDemo1 frame=new DrawDemo1(); 

    frame.show(); 

    frame.comp2D=(Graphics2D)frame.contentPane .getGraphics(); 

    frame.comp2D.setBackground(Color.white); 

    frame.comp2D.clearRect(0,0,401,221); 

   } 



  //Overridden so we can exit when window is closed 

  protected void processWindowEvent(WindowEvent e) { 

    super.processWindowEvent(e); 

    if (e.getID() == WindowEvent.WINDOW_CLOSING) { 

      System.exit(0); 

    } 

  } 



  int Xs1[]={10,60,120,200,260,340}; 

  int Ys1[]={10,200,120,180,60,130}; 



  void jButton1_actionPerformed(ActionEvent e){ 



      comp2D.clearRect(0,0,401,221); 

       //笔宽度      

      float thick = 10f; 

      //设置笔刷 

      //园头园连接 

comp2D.setStroke(new BasicStroke(thick, 

BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); 

      comp2D.setPaint(Color.red); 

      

       //通过该方法使图形去除锯齿状 

      comp2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 

                         RenderingHints.VALUE_ANTIALIAS_ON); 

         comp2D.drawPolyline(Xs1,Ys1,Xs1.length);   

  } 



  void jButton2_actionPerformed(ActionEvent e) { 

      

      comp2D.clearRect(0,0,401,221); 

       //笔宽度      

      float thick = 10f; 

      

      //设置笔刷 

      //方头方连接 

comp2D.setStroke(new BasicStroke(thick, 

BasicStroke.CAP_SQUARE, BasicStroke.CAP_SQUARE)); 

      comp2D.setPaint(Color.blue); 

      

       //通过该方法使图形去除锯齿状 

     //comp2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 

       //                 RenderingHints.VALUE_ANTIALIAS_ON); 

      comp2D.drawPolyline(Xs1,Ys1,Xs1.length);   

  } 



void jButton3_actionPerformed(ActionEvent e) { 

      

      comp2D.clearRect(0,0,401,221); 

       //笔宽度      

      float thick = 1f; 

      

      //设置笔刷 

      //方头方连接 

comp2D.setStroke(new BasicStroke(thick, 

BasicStroke.CAP_SQUARE, BasicStroke.CAP_SQUARE)); 

      

      comp2D.setPaint(Color.blue); 

      

       //通过该方法使图形去除锯齿状 

     //comp2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 

       //                 RenderingHints.VALUE_ANTIALIAS_ON); 

    

      //画封闭线 

     comp2D.drawPolygon(Xs1,Ys1,Xs1.length);   

  } 









二、贝塞尔(Bezier)曲线 



java 2D提供的QuadCurve2D(二次贝塞尔曲线)及 CubicCurve2D(三次贝塞尔曲线)等相关的类,可以很容易的画出贝赛尔曲线。 

QuadCurve2D为三个数据,中间一个为控制点。 

CubicCurve2D为四个数据,中间两个为控制点。 



样例: 



package myDrawDemo; 



import java.awt.*; 

import java.awt.event.*; 

import javax.swing.*; 

import java.awt.geom.*; 



public class DrawDemo1 extends JFrame 



  public JPanel contentPane; //绘图窗口 

  public Graphics2D comp2D;    //绘图对象 

  JPanel jPanel1 = new JPanel();//控件容器 

  JButton jButton1 = new JButton(); 

  JButton jButton2 = new JButton(); 



  //构造函数 

  public DrawDemo1() { 

    enableEvents(AWTEvent.WINDOW_EVENT_MASK); 

    try { 

      jbInit(); 

    } 

    catch(Exception e) { 

      e.printStackTrace(); 

    } 

  } 



  //控件初始化 

  private void jbInit() throws Exception  { 

    contentPane = (JPanel) this.getContentPane(); 

    contentPane.setLayout(new BorderLayout()); 

    this.setSize(new Dimension(400, 300)); 

    this.setTitle("Frame Title"); 

    //contentPane.setSize(400,240); 

    jPanel1.setLayout(null); 

    jButton1.setBounds(new Rectangle(30, 235, 150, 31)); 

    jButton1.setText("二阶贝塞尔"); 



    jButton1.addActionListener(newjava.awt.event.ActionListener() { 

      public void actionPerformed(ActionEvent e){ 

        jButton1_actionPerformed(e); 

      } 

    }); 



    jButton2.setBounds(new Rectangle(200, 235, 150, 30)); 

    jButton2.setText("三阶贝塞尔"); 

   

    jButton2.addActionListener(newjava.awt.event.ActionListener() { 

      public void actionPerformed(ActionEvent e){ 

        jButton2_actionPerformed(e); 

      } 

    }); 



     contentPane.add(jPanel1, BorderLayout.CENTER); 

    jPanel1.add(jButton1, null); 

    jPanel1.add(jButton2, null); 

   

  } 



   public static void main(String[] args) { 

    

    DrawDemo1 frame=new DrawDemo1(); 

    frame.show(); 

    frame.comp2D=(Graphics2D)frame.contentPane.getGraphics(); 

    frame.comp2D.setBackground(Color.white); 

    frame.comp2D.clearRect(0,0,401,221); 

   } 



  //Overridden so we can exit when window is closed 

  protected void processWindowEvent(WindowEvent e) { 

    super.processWindowEvent(e); 

    if (e.getID() == WindowEvent.WINDOW_CLOSING) { 

      System.exit(0); 

    } 

  } 



  

  void jButton1_actionPerformed(ActionEvent e){ 



     double[] x1={50,180,300}; 

     double[] y1={100,190,100}; 



      comp2D.clearRect(0,0,401,221); 

       //笔宽度      

      float thick = 1f; 

      

      comp2D.setPaint(Color.red); 

      

      QuadCurve2D.Double qc=new QuadCurve2D.Double(); 

     qc.setCurve(x1[0],y1[0],x1[1],y1[1],x1[2],y1[2]); 

       

      comp2D.draw(qc); 

      

     comp2D.drawLine((int)x1[1]-5,(int)y1[1],(int)x1[1]+5,(int)y1[1]); 

     comp2D.drawLine((int)x1[1],(int)y1[1]-5,(int)x1[1],(int)y1[1]+5); 

      

      comp2D.setPaint(Color.blue); 

      

      x1[1]=180; 

      y1[1]=30; 

      

     qc.setCurve(x1[0],y1[0],x1[1],y1[1],x1[2],y1[2]); 

       

      comp2D.draw(qc); 

      

      comp2D.drawLine((int)x1[1]-5,(int)y1[1],(int)x1[1]+5,(int)y1[1]); 

     comp2D.drawLine((int)x1[1],(int)y1[1]-5,(int)x1[1],(int)y1[1]+5); 

      

  } 



  void jButton2_actionPerformed(ActionEvent e) { 

      

     double[] x1={50,80,200,300}; 

     double[] y1={100,70,190,100}; 

      

      comp2D.clearRect(0,0,401,221); 

       //笔宽度      

      float thick = 1f; 

      

      comp2D.setPaint(Color.red); 

      

      CubicCurve2D.Double qc=newCubicCurve2D.Double(); 

     qc.setCurve(x1[0],y1[0],x1[1],y1[1],x1[2],y1[2],x1[3],y1[3]); 

       

      comp2D.draw(qc); 

      

     comp2D.drawLine((int)x1[1]-5,(int)y1[1],(int)x1[1]+5,(int)y1[1]); 

     comp2D.drawLine((int)x1[1],(int)y1[1]-5,(int)x1[1],(int)y1[1]+5); 

      

      comp2D.drawLine((int)x1[2]-5,(int)y1[2],(int)x1[2]+5,(int)y1[2]); 

     comp2D.drawLine((int)x1[2],(int)y1[2]-5,(int)x1[2],(int)y1[2]+5); 

      

      float dash1[] = {10.0f}; 

      

      //画虚线 

      BasicStroke dashed = new BasicStroke(1.0f, 

                                        BasicStroke.CAP_BUTT, 

                                        BasicStroke.JOIN_MITER, 

                                        10.0f, dash1, 0.0f); 



      comp2D.setStroke(dashed); 

      comp2D.setPaint(Color.darkGray); 

      comp2D.drawLine((int)x1[1],(int)y1[1],(int)x1[2],(int)y1[2]); 

     

     //画实线 

      BasicStroke stroke = newBasicStroke(1.0f); 

      comp2D.setStroke(stroke); 

      comp2D.setPaint(Color.blue); 

      

      x1[1]=180; 

      y1[1]=70; 

      x1[2]=80; 

      y1[2]=190; 

      

     qc.setCurve(x1[0],y1[0],x1[1],y1[1],x1[2],y1[2],x1[3],y1[3]); 

       

      comp2D.draw(qc); 

      

     comp2D.drawLine((int)x1[1]-5,(int)y1[1],(int)x1[1]+5,(int)y1[1]); 

      comp2D.drawLine((int)x1[1],(int)y1[1]-5,(int)x1[1],(int)y1[1]+5); 

      

     comp2D.drawLine((int)x1[2]-5,(int)y1[2],(int)x1[2]+5,(int)y1[2]); 

     comp2D.drawLine((int)x1[2],(int)y1[2]-5,(int)x1[2],(int)y1[2]+5); 

      

      comp2D.setStroke(dashed); 

      comp2D.setPaint(Color.darkGray); 

     comp2D.drawLine((int)x1[1],(int)y1[1],(int)x1[2],(int)y1[2]); 

      comp2D.setStroke(stroke); 

  } 















    

    三、自定义样条曲线编程 

    

当我们需要平滑多个数据样本点的时候,贝塞尔曲线就不能满足要求了,为此,可以采用最早由美国“波音”飞机制造公司提出来的样条曲线来完成,这种曲线所以称之为样条,是因为它模拟了造船业中的放样原理。 

样条曲线的数学原理请参考计算机图形学,这里给出的是由java编写的三次样条曲线的例子。曲线平滑的原则是,必须通过所有的样本点,另外,不论有多少样本点,曲线的阶次最大为三次,所以是稳定的。 

这里我们可以看出来,程序设计的生命是什么呢?数学!这是程序设计着的生命所在。语言只是一种规范或者是一个工具,要真正写出好的程序,没有深厚的数学功底,是万万不可能的。 



样例: 



package myDrawDemo; 



import java.awt.*; 

import java.awt.event.*; 

import javax.swing.*; 

import java.awt.geom.*; 



public class DrawCurve extends JFrame 



  public JPanel contentPane; //绘图窗口 



  JPanel jPanel1 = new JPanel();//控件容器 

  JButton jButton1 = new JButton(); 

  JButton jButton2 = new JButton(); 

  JButton jButton3 = new JButton(); 



  

  GraphicsCurve gracu; 





  //构造函数 

  public DrawCurve() { 

    enableEvents(AWTEvent.WINDOW_EVENT_MASK); 

    try { 

      jbInit(); 

    } 

    catch(Exception e) { 

      e.printStackTrace(); 

    } 

  } 



    //控件初始化 



    private void jbInit() throws Exception  { 

    contentPane = (JPanel) this.getContentPane(); 

    contentPane.setLayout(new BorderLayout()); 

    this.setSize(new Dimension(500,400)); 

    this.setTitle("Frame Title"); 

    //contentPane.setSize(400,240); 

    jPanel1.setLayout(null); 

    jButton1.setBounds(new Rectangle(30, 310, 100, 31)); 

    jButton1.setText("直线"); 





    jButton1.addActionListener(newjava.awt.event.ActionListener() { 

      public void actionPerformed(ActionEvent e){ 

        jButton1_actionPerformed(e); 

      } 

    }); 





    jButton2.setBounds(new Rectangle(150, 310, 100, 30)); 

    jButton2.setText("样条曲线"); 

   

    jButton2.addActionListener(new java.awt.event.ActionListener(){ 

      public void actionPerformed(ActionEvent e){ 

        jButton2_actionPerformed(e); 

      } 

    }); 

    

    jButton3.setBounds(new Rectangle(270, 310, 100, 30)); 

    jButton3.setText("粗线条"); 

   

    jButton3.addActionListener(newjava.awt.event.ActionListener() { 

      public void actionPerformed(ActionEvent e){ 

        jButton3_actionPerformed(e); 

      } 

    }); 

   

     contentPane.add(jPanel1, BorderLayout.CENTER); 

    jPanel1.add(jButton1, null); 

    jPanel1.add(jButton2, null); 

    jPanel1.add(jButton3, null); 

    

    gracu=new GraphicsCurve(); 

  } 



   public static void main(String[] args) { 

    

    DrawCurve frame=new DrawCurve(); 

    frame.show(); 

    frame.gracu.myGraphics=(Graphics2D)frame.contentPane.getGraphics(); 

    frame.gracu.myGraphics.setBackground(Color.white); 

    frame.gracu.myGraphics.clearRect(0,0,500,300); 

   } 



  //Overridden so we can exit when window is closed 

  protected void processWindowEvent(WindowEvent e) { 

    super.processWindowEvent(e); 

    if (e.getID() == WindowEvent.WINDOW_CLOSING) { 

      System.exit(0); 

    } 

  } 

    int Xs1[]={10,60,120,200,260,340}; 

    int Ys1[]={10,200,120,180,60,130}; 



  //画折线 

  void jButton1_actionPerformed(ActionEvent e){ 

          

      gracu.myGraphics.setPaint(Color.blue); 

     gracu.myGraphics.drawPolyline(Xs1,Ys1,Xs1.length);     

  } 

  

  //画样条  

  void jButton2_actionPerformed(ActionEvent e) { 

      

      gracu.myGraphics.setPaint(Color.red); 

      gracu.DrawCurves(Xs1,Ys1); 

  } 



  //画粗线 

  void jButton3_actionPerformed(ActionEvent e) { 

      //笔宽度      

      float thick = 10f; 

      //设置笔刷 

      //方头园连接 

      //gracu.myGraphics.setStroke(newBasicStroke(thick, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); 

      //园头园连接 

      gracu.myGraphics.setStroke(newBasicStroke(thick, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); 

      gracu.myGraphics.setPaint(Color.blue); 

       //通过该方法使图形去除锯齿状 

      gracu.myGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 

                         RenderingHints.VALUE_ANTIALIAS_ON); 

     gracu.myGraphics.drawPolyline(Xs1,Ys1,Xs1.length);     

         } 

  } 



class GraphicsCurve 



     //绘图对象 

       public Graphics2D myGraphics; 

       

       public GraphicsCurve() 

      {        

        

       } 

       

       public GraphicsCurve(Graphics2Dgraphics) 

      {        

        this.myGraphics=graphics; 

       } 

       //参数表 

       //x数组,y数组,笔刷       

       public void DrawCurves(int[] xa,int[]ya) 

       { 

              

             int[] x, y; 

             double[] a, b, c; 

             double[] px, py, qx, qy, tt; 

             double[] dx, dy; 

             int px1,py1,px2,py2; 

           x=xa; 

             y=ya; 

             px1=x[0]; 

             py1=y[0]; 

             int n=x.length; 

                    a=new double[n]; 

                    b=new double[n]; 

                    c=new double[n]; 

                    px=new double[n]; 

                    py=new double[n]; 

                    qx=new double[n]; 

                    qy=new double[n]; 

                    tt=new double[n]; 

                    dx=new double[n]; 

                    dy=new double[n]; 

                    int i, t, es; 

                    double bx3, bx4, by3, by4, cx, cy; 

                    bx4 = 0; 

                    by3 = 0; 

                    es = 3; 

                    px[0] = 1; 

                    py[0] = 1; 

                    px[n-1] = 1; 

                    py[n-1] = 1; 

                    if (n>1) 

                    { 

                           for (i = 1;i<n;i++) 

                                  tt[i] = Math.sqrt((x[i] - x[i - 1]) * (x[i] - x[i - 1]) + (y[i] - y[i - 1]) *(y[i] - y[i - 1])); 

                           switch(n)       

                           {    

                                  case 2: 

                                         break; 

                                  case 3: 

                                         for (i = 1;i<n - 1;i++) 

                                         { 

                                                a[i] = 2 * (tt[i] + tt[i + 1]); 

                                                b[i] = tt[i + 1]; 

                                                c[i] = tt[i]; 

                                                dx[i] = 3 * (tt[i] * (x[i + 1] - x[i]) / tt[i + 1] + tt[i + 1] * (x[i] - x[i -1]) / tt[i]); 

                                                dy[i] = 3 * (tt[i] * (y[i + 1] - y[i]) / tt[i + 1] + tt[i + 1] * (y[i] - y[i -1]) / tt[i]); 

                                         } 



                                         dx[1] = dx[1] - tt[2] * px[0]; 

                                         dx[n - 2] = dx[n - 2] - tt[n - 2] * px[n-1]; 

                                         dy[1] = dy[1] - tt[2] * py[0]; 

                                         dy[n - 2] = dy[n - 2] - tt[n - 2] * py[n-1]; 



                                         //注意,这是n=3的情况专有计算 

                                         px[1] = dx[1] / a[1]; 

                                         py[1] = dy[1] / a[1]; 

                                          

                                         break; 

                                  default: 

                                         for (i = 1;i<n - 1;i++) 

                                         { 

                                                a[i] = 2 * (tt[i] + tt[i + 1]); 

                                                b[i] = tt[i + 1]; 

                                                c[i] = tt[i]; 

                                                dx[i] = 3 * (tt[i] * (x[i + 1] - x[i]) / tt[i + 1] + tt[i + 1] * (x[i] - x[i -1]) / tt[i]); 

                                                dy[i] = 3 * (tt[i] * (y[i + 1] - y[i]) / tt[i + 1] + tt[i + 1] * (y[i] - y[i -1]) / tt[i]); 

                                         } 

                                         dx[1] = dx[1] - tt[2] * px[0]; 

                                         dx[n - 2] = dx[n - 2] - tt[n - 2] * px[n-1]; 

                                         dy[1] = dy[1] - tt[2] * py[0]; 

                                         dy[n - 2] = dy[n - 2] - tt[n - 2] * py[n-1]; 

                                         c[1] = c[1]/ a[1]; 

                                         for (i = 2 ;i< n - 1;i++) 

                                         { 

                                                a[i] = a[i] - b[i] * c[i - 1]; 

                                                c[i] = c[i] / a[i]; 

                                         } 

                                         qx[1] = dx[1] / a[1]; 

                                         qy[1] = dy[1] / a[1]; 

                                         for (i = 2 ;i< n - 1;i++) 

                                         { 

                                                qx[i] = (dx[i] - b[i] * qx[i - 1]) / a[i]; 

                                                qy[i] = (dy[i] - b[i] * qy[i - 1]) / a[i]; 

                                         } 

                                         px[n - 2] = qx[n - 2]; 

                                         py[n - 2] = qy[n - 2]; 

                                         for (i = n - 3;i>=1;i--) 

                                         { 

                                                px[i] = qx[i] - c[i] * px[i + 1]; 

                                                py[i] = qy[i] - c[i] * py[i + 1]; 

                                         } 

                                         break; 

                           } 

                           for (i = 0 ;i< n - 1;i++) 

                           { 

                                  bx3 = (3 * (x[i + 1] - x[i]) / tt[i + 1] - 2 * px[i] - px[i + 1]) / tt[i +1]; 

                                  bx4 = ((2 * (x[i] - x[i + 1]) / tt[i + 1] + px[i] + px[i + 1]) / tt[i + 1]) /tt[i + 1]; 

                                  by3 = (3 * (y[i + 1] - y[i]) / tt[i + 1] - 2 * py[i] - py[i + 1]) / tt[i +1]; 

                                  by4 = ((2 * (y[i] - y[i + 1]) / tt[i + 1] + py[i] + py[i + 1]) / tt[i + 1]) /tt[i + 1]; 

                                  t = 0; 

                                  while (t < tt[i + 1]) 

                                  { 

                                         t = t + es; 

                                         cx = x[i] + (px[i] + (bx3 + bx4 * t) * t) * t; 

                                         cy = y[i] + (py[i] + (by3 + by4 * t) * t) * t; 

                                         px2 = (int)cx; 

                                         py2 = (int)cy; 

                                         myGraphics.drawLine(px1,py1,px2,py2); 

                                         px1 = px2; 

                                         py1 = py2; 

                                  } 

                           } 

                    }                          

       } 













    四、用户数据的曲线显示 



当需要用曲线表达数据的时候,我们虽然可以使用由厂家提供的“图表”组件,但更多的还是需要自己编写的,请仔细研究下面的程序,当对图表设计有更深入的理解。 

下面的例子,我们构造一个专门处理用户数据的类,在这个类里,实现了用户坐标和屏幕坐标的转换,同时给出了一个自动绘制坐标的方法。我们也直接使用了上面我们讨论过的样条曲线的类实现数据平滑。例子中的数据可以来自于数据库或其它任何地方,仔细的研究这个例子,可以看出只要我们开动脑筋,把java强大的功能和我们对问题的理解结合在一起,就可以写出多么灵活多变的程序来呀! 



样例: 



package myDrawDemo; 



import java.awt.*; 

import java.awt.event.*; 

import javax.swing.*; 

import javax.swing.event.*; 

import java.awt.geom.*; 



public class DataDrawDemo extends JFrame 



  public JPanel contentPane; //控件容器 

  

  JPanel jPanel1 = new JPanel();//绘图控件 

  

  JButton jButton1 = new JButton(); 

  JButton jButton2 = new JButton(); 

  JButton jButton3 = new JButton(); 

  JButton jButton4 = new JButton(); 

  JButton jButton5 = new JButton(); 



  JButton jButton6 = new JButton(); 

  JButton jButton7 = new JButton(); 

  JButton jButton8 = new JButton(); 

  JButton jButton9 = new JButton(); 



  JButton jButton10 = new JButton(); 

  

  JTextField jText1=new JTextField(); 



  JTextField jText2=new JTextField(); 



  boolean kcu=true; 

  

  //用户坐标转换对象 

  myGraphicsData mp=new myGraphicsData(); 

  

  //曲线转换对象 

  GraphicsCurve gracu=new GraphicsCurve(); 

  

  

    //窗口范围 

    double wx1,wx2,wy1,wy2; 



  //构造函数 

  public DataDrawDemo() { 

    enableEvents(AWTEvent.WINDOW_EVENT_MASK); 

    try { 

      jbInit(); 

    } 

    catch(Exception e) { 

      e.printStackTrace(); 

    } 

  } 



    //初始化代码 

    private void jbInit() throws Exception  { 



    

    contentPane = (JPanel) this.getContentPane(); 

    contentPane.setLayout(null); 

   

    this.setSize(new Dimension(650, 500)); 

    this.setTitle("Frame Title"); 

    //contentPane.setSize(400,240); 

    //jPanel1.setLayout(null); 



    jPanel1.setBounds(0,90,650,420); 

    jButton1.setBounds(new Rectangle(30, 20, 80, 25)); 

    jButton1.setText("开始"); 



    jButton1.addActionListener(newjava.awt.event.ActionListener() { 

      public void actionPerformed(ActionEvent e){ 

        jButton1_actionPerformed(e); 

      } 

    }); 



    jButton2.setBounds(new Rectangle(120, 20, 80, 25)); 

    jButton2.setText("左移"); 

   

    jButton2.addActionListener(new java.awt.event.ActionListener(){ 

      public void actionPerformed(ActionEvent e){ 

        jButton2_actionPerformed(e); 

      } 

    }); 



    jButton3.setBounds(new Rectangle(210, 20, 80, 25)); 

    jButton3.setText("右移"); 

   

    jButton3.addActionListener(newjava.awt.event.ActionListener() { 

      public void actionPerformed(ActionEvent e){ 

        jButton3_actionPerformed(e); 

      } 

    }); 



   jButton4.setBounds(new Rectangle(300, 20, 80, 25)); 

    jButton4.setText("上移"); 

   

    jButton4.addActionListener(newjava.awt.event.ActionListener() { 

      public void actionPerformed(ActionEvent e){ 

        jButton4_actionPerformed(e); 

      } 

    }); 



  jButton5.setBounds(new Rectangle(390, 20, 80, 25)); 

    jButton5.setText("下移"); 

   

    jButton5.addActionListener(newjava.awt.event.ActionListener() { 

      public void actionPerformed(ActionEvent e){ 

        jButton5_actionPerformed(e); 

      } 

    }); 

    

    jButton6.setBounds(new Rectangle(120, 50, 80, 25)); 

    jButton6.setText("X扩"); 

   

    jButton6.addActionListener(newjava.awt.event.ActionListener() { 

      public void actionPerformed(ActionEvent e){ 

        jButton6_actionPerformed(e); 

      } 

    }); 



    jButton7.setBounds(new Rectangle(210, 50, 80, 25)); 

    jButton7.setText("X缩"); 

   

    jButton7.addActionListener(newjava.awt.event.ActionListener() { 

      public void actionPerformed(ActionEvent e){ 

        jButton7_actionPerformed(e); 

      } 

    }); 



   jButton8.setBounds(new Rectangle(300, 50, 80, 25)); 

    jButton8.setText("Y扩"); 

   

    jButton8.addActionListener(newjava.awt.event.ActionListener() { 

      public void actionPerformed(ActionEvent e){ 

        jButton8_actionPerformed(e); 

      } 

    }); 



    jButton9.setBounds(new Rectangle(390, 50, 80, 25)); 

    jButton9.setText("Y缩"); 

   

    jButton9.addActionListener(newjava.awt.event.ActionListener() { 

      public void actionPerformed(ActionEvent e){ 

        jButton9_actionPerformed(e); 

      } 

    }); 

    

    //样条控制    

    jButton10.setBounds(new Rectangle(30, 50, 80, 25)); 

    jButton10.setText("样条"); 



    jButton10.addActionListener(newjava.awt.event.ActionListener() { 

      public void actionPerformed(ActionEvent e){ 

        jButton10_actionPerformed(e); 

      } 

    }); 



    jText1.setBounds(new Rectangle(490, 20, 120, 20)); 

    jText1.setText(""); 

  

    jText2.setBounds(new Rectangle(490, 50, 120, 20)); 

    jText2.setText(""); 

  

  

    //鼠标按下侦听器 

    jPanel1.addMouseListener(newjava.awt.event.MouseAdapter(){ 

       public void mousePressed(MouseEvent e){ 

       JPanel_mousePressed(e); 

   

     } 

        

   }); 

   

    //鼠标拖动侦听器 

    jPanel1.addMouseMotionListener(newjava.awt.event.MouseMotionAdapter(){ 

       public void mouseDragged(MouseEvente){ 

       JPanel_mouseDragged(e); 

     } 

    }); 

    

    

    //鼠标释放侦听器 

    jPanel1.addMouseListener(newjava.awt.event.MouseAdapter(){ 

       public void mouseReleased(MouseEvent e){ 

       JPanel_mouseReleased(e); 

     } 

   }); 

   

    contentPane.add(jPanel1, BorderLayout.CENTER); 

    

    contentPane.add(jButton1, null); 

    contentPane.add(jButton2, null); 

    contentPane.add(jButton3, null); 

    contentPane.add(jButton4, null); 

    contentPane.add(jButton5, null); 

    contentPane.add(jButton6, null); 

    contentPane.add(jButton7, null); 

    contentPane.add(jButton8, null); 

    contentPane.add(jButton9, null); 

    contentPane.add(jButton10, null); 

    contentPane.add(jText1, null); 

    contentPane.add(jText2, null); 

  } 



   public static void main(String[] args) { 

    

    DataDrawDemo frame=new DataDrawDemo(); 

    frame.show(); 

    frame.gracu.myGraphics=(Graphics2D)frame.jPanel1.getGraphics(); 

   frame.mp.myGraphics=(Graphics2D)frame.jPanel1.getGraphics(); 

    frame.mp.myGraphics.setBackground(Color.white); 

    frame.mp.myGraphics.clearRect(0,0,650,375); 

   } 

        //第一组数据 

             double[] Xs1=new double[]{-2,2,4,6,8,10,12,14}; 

             double[] Ys1=new double[]{-4,10,3,14,4,10,6,7}; 

             //第二组数据 

             double[] Xs2=new double[]{-1,2,4,6,8,10,12,14,16}; 

             double[] Ys2=new double[]{1,5,7,1,13,11,4,10,8}; 

     //这是一个画曲线的程序 

       void DwData() 

       { 

         //剪裁,可以试试没有剪裁是什么表现? 

      mp.myGraphics.clipRect(10,10,621,351); 

      //由于是用两个对象绘图,所以应该分别剪切 

      gracu.myGraphics.clipRect(10,10,621,351);  

         //清除绘图空间     

         mp.myGraphics.clearRect(0,0,650,375); 

      //用户坐标和屏幕坐标转换 

      mp.truemode(10,630,10,360,wx1,wx2,wy1,wy2); 

          //设置颜色              

      mp.myGraphics.setPaint(Color.darkGray); 

       //画边框 

       mp.myGraphics.drawRect(10,10,620,350); 

       mp.myGraphics.setFont(new Font("宋体", 0,10)); //9为字大小 

       //画坐标 

      mp.axis(2,2,2,2);                   

       //画红线  

       int[] x=new int[Xs1.length]; 

       int[] y=new int[Ys1.length]; 

       int[] myxy; 

       //统一实现坐标转换       

       for (int i=0;i<x.length;i++) 

       { 

          myxy=mp.moxy(Xs1[i],Ys1[i]); 

          x[i]=myxy[0]; 

          y[i]=myxy[1]; 

       } 

       if (kcu) 

       { 

        mp.myGraphics.setPaint(Color.red); 

        mp.myGraphics.drawPolyline(x,y,x.length); 

       } 

       else 

       { 

        gracu.myGraphics.setPaint(Color.red); 

        gracu.DrawCurves(x,y); 

       } 

       //画蓝线 

       x=new int[Xs2.length]; 

       y=new int[Ys2.length]; 

       for (int i=0;i<x.length;i++) 

       { 

          myxy=mp.moxy(Xs2[i],Ys2[i]); 

          x[i]=myxy[0]; 

          y[i]=myxy[1]; 

       } 

       if (kcu) 

       { 

        mp.myGraphics.setPaint(Color.blue); 

        mp.myGraphics.drawPolyline(x,y,x.length); 

       } 

       else 

       { 

        gracu.myGraphics.setPaint(Color.blue); 

        gracu.DrawCurves(x,y); 

      }           

  } 

              

  //退出窗口事件 

  protected void processWindowEvent(WindowEvent e) { 

    super.processWindowEvent(e); 

    if (e.getID() == WindowEvent.WINDOW_CLOSING) { 

      System.exit(0); 

    } 

  } 

  

  //鼠标按下事件 

  void JPanel_mousePressed(MouseEvent e) 

  { 

      double[]zs=mp.ScrtoCon(e.getX(),e.getY()); 

      jText1.setText(String.valueOf((float)zs[0]));  

     jText2.setText(String.valueOf((float)zs[1]));  

  } 



  //鼠标释放事件 

  void JPanel_mouseReleased(MouseEvent e) 

  { 

      double[]zs=mp.ScrtoCon(e.getX(),e.getY()); 

     jText1.setText("");    

      jText2.setText(""); 

      

       //画红线  

      mp.myGraphics.setPaint(Color.darkGray); 

     mp.myGraphics.drawLine(e.getX()-3,e.getY(),e.getX()+3,e.getY()); 

     mp.myGraphics.drawLine(e.getX(),e.getY()-3,e.getX(),e.getY()+3); 

      mp.myGraphics.drawString(String.valueOf((float)zs[0]),e.getX()+10,e.getY());        

     mp.myGraphics.drawString(String.valueOf((float)zs[1]),e.getX()+10,e.getY()+12);  

  } 



  //鼠标拖动事件 

  void JPanel_mouseDragged(MouseEvent e) 

  { 

      double[] zs=mp.ScrtoCon(e.getX(),e.getY()); 

     jText1.setText(String.valueOf((float)zs[0]));  

     jText2.setText(String.valueOf((float)zs[1]));  

  } 

  

  //开始  

  void jButton1_actionPerformed(ActionEvent e){ 



          wx1=1000000; 

          wy1=1000000; 

          wx2=-1000000; 

          wy2=-1000000; 

  

          //试验中数据来自一个数组,实际中可来自任何地方 

   //设置初始范围 

   for (int i=0;i<Xs1.length;i++) 

   { 

       if (Xs1[i]< wx1) 

          wx1=Xs1[i]; 

       if (Xs1[i]> wx2) 

          wx2=Xs1[i]; 

       

      if (Ys1[i]< wy1) 

          wy1=Ys1[i]; 

       if (Ys1[i]> wy2) 

          wy2=Ys1[i]; 

     } 

  for (int i=0;i<Xs2.length;i++) 

   { 

       if (Xs2[i]< wx1) 

          wx1=Xs2[i]; 

       if (Xs2[i]> wx2) 

          wx2=Xs2[i]; 

      if (Ys2[i]< wy1) 

          wy1=Ys2[i]; 

      if (Ys2[i]> wy2) 

          wy2=Ys2[i]; 

     } 

    DwData(); 

  } 



  //左移 

  void jButton2_actionPerformed(ActionEvent e) { 

      

    wx1-=1; 

    wx2-=1;  

    DwData(); 

  } 

  

  //右移 

   void jButton3_actionPerformed(ActionEvent e) { 

      

    

      wx1+=1; 

      wx2+=1;  

      DwData(); 

  } 

  

  //上移 

  void jButton4_actionPerformed(ActionEvent e) { 

      

    wy1-=1; 

    wy2-=1;  

    DwData(); 

  } 



  //下移 

  void jButton5_actionPerformed(ActionEvent e) { 

      

    wy1+=1; 

    wy2+=1;  

    DwData(); 

  } 

  

  //X扩 

  void jButton6_actionPerformed(ActionEvent e) { 

      

    wx1-=1; 

    wx2+=1;  

    DwData(); 

  } 

  

  //X缩 

  void jButton7_actionPerformed(ActionEvent e) { 

      

    wx1+=1; 

    wx2-=1;  

    DwData(); 

  } 

  

  //Y扩 

  void jButton8_actionPerformed(ActionEvent e) { 

      

    wy1-=1; 

    wy2+=1;  

    DwData(); 

  } 



  //Y缩 

  void jButton9_actionPerformed(ActionEvent e) { 

      

    wy1+=1; 

    wy2-=1;  

    DwData(); 

  } 



  //样条控制 

  void jButton10_actionPerformed(ActionEvent e) { 

      

    if (kcu) 

    { 

          jButton10.setText("直线"); 

           kcu=false; 

    } 

    else 

    { 

          jButton10.setText("样条"); 

           kcu=true; 

    } 

    DwData(); 

  } 





//图形处理类 

class myGraphicsData 



       //屏幕坐标 

       private int X11, Y11, X12, Y12;//x1,y1,x2,y2 

       //用户坐标 

       private double W1, W2, W3, W4;//x1,x2,y1,y2 

       //绘图对象 

       public Graphics2D myGraphics; 

       double Ax8, Ay8; 

       //用户窗口与屏幕窗口的转换 

       //x1,x2,,y1,y2为屏幕坐标 

       //wx1,wx2,wy1,wy2为用户坐标 

       

       public void truemode(int x1, int x2, inty1,int y2, double wx1, double wx2, double wy1, double wy2) 

       { 

             X11 = x1 ; X12 = x2; 

             Y11 = y1 ; Y12 = y2; 

             W1 = wx1 ; W2 = wx2; 

             W3 = wy1 ; W4 = wy2; 

             Ax8 = (X12 - X11) / (wx2 - wx1); 

             Ay8 = (Y12 - Y11) / (wy2 - wy1); 

       } 



       //把用户坐标转为屏幕坐标 

       public int[] moxy(double Xa, doubleYa) 

       { 

             int[] myout=new int[2]; 

             myout[0] = (int)(Ax8 * (Xa - W1) + X11); 

             myout[1] = (int)(Y12 - Ay8 * (Ya - W3)); 

             return myout; 

       } 



       //把屏幕坐标转为用户坐标 

       public double[] ScrtoCon(int X6, intY6) 

       { 

             double[] myout=new double[2]; 

             myout[0] = (X6 - X11) / Ax8 + W1; 

             myout[1] = (Y12 - Y6) / Ay8 + W3; 

             return myout; 

       } 



       //画线 

       public void Dline(double xa, double ya,double xb, double yb) 

       { 

             try 

             { 

                    int x6, y6, x7, y7; 

                    x6 = (int)(Ax8 * (xa - W1) + X11); 

                    y6 = (int)(Y12 - Ay8 * (ya - W3)); 

                    x7 = (int)(Ax8 * (xb - W1) + X11); 

                    y7 = (int)(Y12 - Ay8 * (yb - W3)); 

                    myGraphics.drawLine(x6, y6, x7, y7); 

             } 

             catch(Exception e){} 

       } 





       //画坐标U,V为 X,Y轴单位,ns,nt为 x,y轴写字间隔 



       public void axis(double u, double v, intns, int nt) 

       { 

             double p9, q9, s; 

             int n2, swx,swy; 

             int xk=0; 

             int yk=0; 

             double ge; 

             int[] showxy=new int[2]; 

             swx = 0; 

             swy=4; 

             ge = (double)0.008 * (W2 - W1); 

             p9 = W1; 

             q9 = (double)(W3 + (W4 - W3) * 0.05); 

             if ((W1 < 0) && (W2 > 0)) p9 = 0; 

             if ((W3 < 0) && (W4 > 0)) q9 = 0; 

             Dline(p9, W3, p9, W4); 

             n2 = 0; 

             s = 0; 

             while (s < W4) 

             { 

                    Dline(p9, s, p9 + ge, s); 

                    if (n2 >= nt) 

                    { 

                           Dline(p9, s, p9 + ge + ge, s); 

                           n2 = 1; 

                           showxy=moxy(p9 + ge + ge,s); 

                           myGraphics.drawString(String.valueOf(s),showxy[0] - swx+4, showxy[1] -swy+4); 

                    } 

                    else 

                    { 

                           n2++; 

                    } 

                    s += v; 

             }                   

             //End While 

             s = 0; 

             n2 = 0; 

             while (s > W3) 

             { 

                    Dline(p9, s, p9 + ge, s); 

                    if (n2 >= nt) 

                    { 

                           Dline(p9, s, p9 + ge + ge, s); 

                           n2 = 1; 

                           showxy=moxy(p9 + ge + ge, s); 

                       myGraphics.drawString(String.valueOf(s),showxy[0] - swx+4, showxy[1] -swy+4); 

                           } 

                    else 

                    { 

                           n2 ++; 

                    } 

                    s -= v; 

             } 

             //End While 

             Dline(W1, q9, W2, q9); 

             ge = (float)(0.008 * (W4 - W3)); 

             n2 = 0; 

             s = 0; 

             while (s < W2) 

             { 

                    Dline(s, q9, s, q9 + ge); 

                    if (n2 >= ns) 

                    { 

                           Dline(s, q9, s, q9 + ge + ge); 

                           n2 = 1; 

                           showxy=moxy(s, q9); 

                       myGraphics.drawString(String.valueOf(s),showxy[0] - swx, showxy[1] -swy-4); 

                    } 

                    else 

                    { 

                           n2 ++; 

                    } 

                    s += u; 

             }                   

             //End While 

             s = 0; 

             n2 =0 ; 

             while (s > W1) 

             { 

                    Dline(s, q9, s, q9 + ge); 

                    if (n2 >= ns) 

                    { 

                           Dline(s, q9, s, q9 + ge + ge); 

                           n2 = 1; 

                           showxy=moxy(s, q9); 

                        myGraphics.drawString(String.valueOf(s),showxy[0] - swx, showxy[1] -swy-4); 

                 } 

                    else 

                    { 

                           n2 ++; 

                    } 

                    s -= u; 

             }            

             //End While 

       } 





// GraphicsCurve类与子定义样条曲线相同 















五、曲线用Applet显示的数据来源问题 



如果需要Applet显示曲线图形,就牵涉到如何提供数据的问题,最简单的办法,是在站点上放置一个有关数据的文本文件,由Applet直接调用这个文本文件,从而读出数据来。但这种办法缺乏必要的灵活性,也是不受推荐的。关键是要能调用数据库数据。当然,经过某些特殊的处理,Applet调用服务器端的数据库也不是不可能,不过这样一来将会带来很多安全隐患,在实用中价值不大。比较好的办法,是在服务器端设置一个动态网页,由这个网页调用数据库,而Applet则通过这个网页取得数据库的数据,由于动态网页的调用是在服务器中执行的,这种方法无论在安全性还是效率上效果都比较好,我们下面来具体讨论一下这种方法。 

为了讨论简单,这种动态网页使用最简单的ASP,其它如JSP等的写法,和这个例子是相似的。 

数据库 

数据处理页面 

jsp 

asp等 

Applet 

 

你可能感兴趣的:(Java:Java2D高级绘图)