源码下载 第3章Java图形处理和Java 2D Java语言的类库提供了丰富的绘图方法,其中大部分对图形、文本、图像的操作方法都定义在Graphics类中,Graphics类是java.awt程序包的一部分。本章介绍的内容包括颜色设置、字体处理、基本图形绘制方法、文本处理,以及Java 2D中Graphics2D提供的基本图形绘制和图形特殊效果处理等方面。 3.1Java图形坐标系统和图形上下文 如果要将图形在屏幕上绘制出来,必须有一个精确的图形坐标系统来给该图形定位。与大多数其他计算机图形系统所采用的二维坐标系统一样,Java的坐标原点(0,0)位于屏幕的左上角,坐标度量以像素为单位,水平向右为X轴的正方向,竖直向下为Y轴的正方向,每个坐标点的值表示屏幕上的一个像素点的位置,所有坐标点的值都取整数,如图31所示。这种坐标系统与传统坐标系统(如图32所示)有所不同。 图31Java图形坐标系统 图32传统坐标系统 在屏幕上绘制图形时,所有输出都是通过一个图形上下文(Graphics Context)来产生的。图形上下文有时也称为图形环境,指允许用户在屏幕上绘制图形的信息,它由Graphics类封装,可以通过Component类的getGraphics()方法获得。图形上下文表示一个绘制图层,例如组件的显示区、打印机上的一页或一个屏幕外图像缓冲区。它提供了绘制3种图形对象(形状、文本和图像)的方法。 在Java中,可以通过Graphics的对象对图形上下文进行管理。Graphics类定义了多种绘图函数,用户可以通过这些函数实现不同的图形绘制和处理。 在游戏编程开发中,经常在组件的paint()方法内获得java.awt包中的Graphics类的对象,然后调用Graphics类中相应的绘制函数实现输出。paint()方法是java.awt.Component 类(所有窗口对象的基类)提供的一个方法,当系统需要重新绘制组件时将调用该方法。paint()方法只有一个参数,该参数是 Graphics 类的实例。下面给出一个实例。 public void paint(Graphics g) {Color myColor= new Color(255, 0, 0); g.setColor(myColor); g.drawString("这是Java中带颜色的文字串", 100,100) ; g.drawRect( 10,10,100 ,100) ; } 组件的绘制时机如下: (1) 当组件的外观发生变化时,例如窗口的大小、位置、图标等有更新,AWT将自动从高层到叶结点组件相应地调用paint()方法,但可能有迟后感。 (2) 程序员也可直接调用某个组件的repaint()或paint()方法,以立即更新外观(例如在添加新的显示内容后)。 注意: 如果要求保留上次的输出结果,可以调用paint(); 如果不要求保留上次的输出结果,只希望用户看到最新的输出结果,可以调用repaint()。 3.2Color类 用户可以使用java.awt.Color类为绘制的图形设置颜色。Color类使用了标准RGB(standard RGB,sRGB)颜色空间来表示颜色值。颜色由红(R)、绿(G)、蓝(B)三原色构成,每种原色的强度用一个byte值表示,每种原色的取值为0(最暗)~255(最亮),这3种颜色值的不同组合显示不同的颜色效果,例如(0,0,0)表示黑色,(255,255,255)表示白色。 在Java中Color类定义了13种颜色常量供用户使用,它们分别为Color.black、Color.blue、Color.cyan、Color.darkGray、Color.gray、Color.green、Color.lightGray、Color.magenta、Color.orange、Color.pink、Color.red、Color.white和Color.yellow。从JDK1.4开始,可以使用Color类中定义的新常量,它们和上述颜色常量一一对应,分别为Color.BLACK、Color.BLUE、Color.CYAN、Color.DARK_GRAY、Color.GRAY、Color.GREEN、Color.LIGHT_GRAY、Color.MAGENTA、Color.ORANGE、Color.PINK、Color.RED、Color.WHITE和Color.YELLOW。 除此之外,用户也可以通过Color类提供的构造方法Color(int r,int g,int b)创建自己需要的颜色。该构造方法通过指定红、绿、蓝3种颜色的值来创建一个新的颜色,参数r、g、b的取值范围为0~255。例如: Color color=new Color(255,0,255); 一旦用户生成了自己需要的颜色,就可以通过java.awt.Component类中的setBackground(Color c)和setForeground(Color c)方法来设置组件的背景色和前景色,也可以将该颜色作为当前的绘图颜色。 3.3Font类和FontMetrics类 3.3.1Font类 用户可以使用java.awt.Font类创建字体对象。在Java中提供了物理字体和逻辑字体两种字体。AWT定义了5种逻辑字体,分别为SansSerif、Serif、Monospaced、Dialog和DialogInput。 Font类的构造方法为: Font(String name,int style,int size); 其中,参数name为字体名,可以设置为系统上可用的任一字体,例如SansSerif、Serif、Monospaced、Dialog或DialogInput等; 参数style为字形,可以设置为Font.PLAIN、Font.BOLD、Font.ITALIC或Font.BOLD + Font.ITALIC等; 参数size为字号,其取值为正整数。例如: Font font=new Font("Serif",Font.ITALIC,10); 如果需要找到系统上的所有可用字体,可以通过创建java.awt.GraphicsEnviroment类的静态方法getLocalGraphicsEnviroment()的实例,调用GetAllFonts()方法来获得系统中的所有可用字体,或通过getAvailableFontFamilyNames()方法来获得可用字体的名字。例如 在生成可用的字体对象后,可以通过java.awt.Component类中的setFont(Font f)方法设置组件的字体。 【例31】在控制台上输出系统中所有的可用字体。程序源代码见ShowAvaliableFont.java,程序运行结果如图33所示。 //ShowAvaliableFont.java import java.awt.*; public class ShowAvaliableFont { public static void main(String[] args) { GraphicsEnvironment e= GraphicsEnvironment.getLocalGraphicsEnvironment(); String[] fontNames=e.getAvailableFontFamilyNames(); //获得可用字体的名称 int j=0; for(int i=0; i < fontNames.length; i++) { System.out.printf("%25s",fontNames[i]); j++; if(j%3==0) System.out.println(); } } } 图33例31的运行结果 3.3.2FontMetrics类 使用drawString(String s,int x,int y)方法可以指定在框架的(x,y)位置开始显示字符串,但是如果想在框架的中央显示字符串,需要使用FontMetrics类。FontMetrics类是一个抽象类,如果要使用FontMetrics对象,可以通过调用Graphics类中的getFontMetrics()方法。FontMetrics定义字体的度量,给出了关于在特定的组件上描绘特定字体的信息。这些字体信息包括ascent(上升量)、descent(下降量)、leading(前导宽度)和height(高度)。其中leading用于描述两行文本间的间距,如图34所示。 图34字体信息示意图 FontMetrics类提供了下面几种方法用于获取ascent、descent、leading和height。  int getAscent(): 取得由当前FontMetrics对象描述的字体的ascent值。  int getDescent(): 取得由当前FontMetrics对象描述的字体的descent值。  int getLeading(): 取得由当前FontMetrics对象描述的字体的leading值。  int getHeight(): 取得使用当前字体的一行文本的标准高度。 【例32】在框架的中央位置显示字符串“Java Programming”,并将字体设置为Serif、粗斜体,大小为30,颜色为红色,将框架背景设置为淡灰色。程序源代码见FontMetricsDemo.java,程序运行结果如图35所示。 //FontMetricsDemo.java import java.awt.*; import javax.swing.JFrame; public class FontMetricsDemo extends JFrame{ public FontMetricsDemo() { super(); setTitle("FontMetrics Demo"); setSize(300,200); setVisible(true); } public void paint(Graphics g) { Font font=new Font("Serif",Font.BOLD+Font.ITALIC,30); //建立字体 g.setFont(font);//设置当前使用字体 setBackground(Color.LIGHT_GRAY);//设置框架的背景颜色 g.setColor(Color.RED); FontMetrics f=g.getFontMetrics(); //建立FontMetrics对象 int width=f.stringWidth("Java Programming");//取得字符串的宽度 int ascent=f.getAscent();//取得当前使用字体的ascent值 int descent=f.getDescent();//取得当前使用字体的descent值 int x=(getWidth()-width)/2; int y=(getHeight()+ascent)/2; g.drawString("Java Programming",x,y); } public static void main(String[] args) { FontMetricsDemo fmd=new FontMetricsDemo(); fmd.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } } 图35例32的运行结果 3.4常用的绘图方法 3.4.1绘制直线 在Java中可以使用下面的方法绘制一条直线: drawLine(int x1,int y1,int x2,int y2); 其中,参数x1、y1、x2、y2分别表示该直线的起点(x1,y1)和终点(x2,y2)的坐标值。 3.4.2绘制矩形 在Java中提供了绘制空心矩形(只绘制矩形的轮廓)和填充矩形的方法,对于普通直角矩形、圆角矩形和三维矩形有不同的绘制方法。 1. 普通直角矩形 用户可以使用下面的方法绘制普通直角矩形的轮廓: drawRect(int x,int y,int width,int height); 如果需要绘制一个有填充颜色的普通直角矩形,可以使用下面的方法: fillRect(int x,int y,int width,int height); 这两种方法的参数的含义相同,x、y分别表示矩形左上角的x坐标和y坐标,width、height分别表示矩形的宽和高。 2. 圆角矩形 用户可以使用下面的方法绘制圆角矩形的轮廓: drawRoundRect(int x,int y,int width,int height,int arcWidth,int arcHeight); 如果需要绘制一个有填充颜色的圆角矩形,可以使用下面的方法: fillRoundRect(int x,int y,int width,int height,int arcWidth,int arcHeight); 图36绘制圆角矩形示意图 这两种方法的参数的含义相同,x、y分别表示矩形左上角的x坐标和y坐标,width、height分别表示矩形的宽和高,arcWidth和arcHeight分别表示圆角弧的水平直径和竖直直径,如图36所示。 3. 三维矩形 用户可以使用下面的方法绘制三维矩形的轮廓: draw3DRect(int x,int y,int width,int height,boolean raised); 如果需要绘制一个有填充颜色的三维矩形,可以使用下面的方法: fill3DRect(int x,int y,int width,int height,boolean raised); 这两种方法的参数的含义相同,x、y分别表示矩形左上角的x坐标和y坐标,width、height分别表示矩形的宽和高,raised为真(true)表示矩形从表面凸起,raised为假(false)表示矩形从表面凹进。 3.4.3绘制椭圆 用户可以使用下面的方法绘制空心椭圆: drawOval(int x,int y,int width,int height); 如果需要绘制一个有填充颜色的椭圆,可以使用下面的方法: fillOval(int x,int y,int width,int height); 图37绘制椭圆示意图 这两种方法的参数的含义相同,x、y分别表示该椭圆的外接矩形左上角的x坐标和y坐标,width、height分别表示外接矩形的宽和高,如图37所示。如果设置外接矩形为正方形,即width和height相等,则可以绘制圆。 【例33】在框架中绘制直线、矩形和椭圆。程序源代码见DrawImageDemo.java,程序运行结果如图38所示。 //DrawImageDemo.java import java.awt.*; import javax.swing.*; public class DrawImageDemo extends JFrame{ public DrawImageDemo() { super(); setTitle("Draw Line Rectangle Ellipse"); setSize(300,300); setVisible(true); } public void paint(Graphics g) { //绘制直线、空心矩形和空心椭圆 g.setColor(Color.red); g.drawRect(10,30,getWidth()/2-50,getHeight()/2-50); g.drawOval(10,30,getWidth()/2-50,getHeight()/2-50); g.drawLine(10,30,5+getWidth()/2-50,30+getHeight()/2-50); //绘制填充色为淡灰色的3D矩形、圆角矩形和椭圆 g.setColor(Color.LIGHT_GRAY); g.fill3DRect(10,180,getWidth()/2-50,getHeight()/2-50,true); g.fillRoundRect(130,30,getWidth()/2-50,getHeight()/2-50,30,40); g.fillOval(130,180,getWidth()/2,getHeight()/2-50); } public static void main(String[] args) { DrawImageDemo d=new DrawImageDemo(); d.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } } 图38例33的运行结果 3.4.4绘制弧形 弧形可以看作椭圆的一部分,因此它的绘制也是根据其外接矩形进行的。通过drawArc()方法和fillArc()方法可以分别绘制弧线和扇形。这两种方法如下: drawArc(int x,int y,int width,int height,int startAngle,int arcAngle); fillArc(int x,int y,int width,int height,int startAngle,int arcAngle); 其中,x、y、width、height参数的含义和drawOval()方法的参数的含义相同,参数startAngle表示该弧的起始角度,参数arcAngle表示生成角度(从startAngle开始转了多少度),且水平向右方向表示0度,从0度开始沿逆时针方向旋转为正角,如图39所示。 图39绘制弧形示意图 3.4.5绘制多边形和折线段 1. 绘制多边形 使用drawPolygon()方法和fillPolygon()方法可以分别绘制多边形的外框轮廓和填充多边形: drawPolygon(int[] xPoints,int[] yPoints,int nPoints); fillPolygon(int[] xPoints,int[] yPoints,int nPoints); 其中,多边形的顶点是由数组xPoints和yPoints中对应下标的相应元素组成的坐标来指定,数组xPoints存储所有顶点的x坐标,数组yPoints存储所有顶点的y坐标,参数nPoints指定多边形的顶点个数。drawPolygon()方法在绘制多边形时并不自动关闭多边形的最后一条边,而是一段开放的折线。所以,若想绘制封闭的边框型多边形,不要忘了在数组的尾部再添上一个起始点的坐标。 除此以外,drawPolygon(Polygon p)方法和fillPolygon(Polygon p)方法也可以用来绘制多边形。这两种方法的参数是一个Polygon类的对象。 若想在多边形上增加一个顶点,可以使用addPoint(int x,int y)方法。因此可以先创建一个空的Polygon对象,再重复调用addPoint()方法将所有多边形的顶点加入创建的Polygon对象中,然后通过调用drawPolygon(Polygon p)方法或fillPolygon(Polygon p)方法绘制多边形。 2. 绘制折线段 使用drawPolygonline()方法可以绘制折线段: drawPolygonline(int[] xPoints,int[] yPoints,int nPoints); 其中,数组xPoints存储所有顶点的x坐标,数组yPoints存储所有顶点的y坐标,nPoints指定折线段顶点的个数。 【例34】在JPanel中绘制扇形和星形。程序源代码见SimpleDraw.java,程序运行结果如图310所示。 //SimpleDraw.java import java.awt.*; import javax.swing.*; public class SimpleDraw { public static void main(String[] args) { DrawFrame frame=new DrawFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } } class DrawFrame extends JFrame { public DrawFrame() { setTitle("简单图形绘制"); setSize(300,300); DrawPanel panel=new DrawPanel(); Container contentPane=getContentPane(); contentPane.add(panel); } } class DrawPanel extends JPanel { public void paintComponent(Graphics g){ super.paintComponent(g); int x1=50,y1=50,x2=50,y2=150; int radius=100;//半径 int startAngle=-90;  //起始角度 int arcAngle=180;   //弧的角度 g.drawLine(x1,y1,x2,y2);   //绘制直线 g.drawArc(x1-radius/2,y1,radius,radius,startAngle,arcAngle); Polygon p=new Polygon(); x1 +=150; y1 +=50; radius /=2; for (int i=0; i < 6; i++) p.addPoint((int)(x1 + radius * Math.cos(i * 2 * Math.PI / 6)), (int)(y1 + radius * Math.sin(i * 2 * Math.PI / 6))); g.drawPolygon(p);   //绘制六边形 } } 图310例34的运行结果 3.4.6清除绘制的图形 使用clearRect()方法可以清除绘制的图形: clearRect(int x,int y,int width,int height); 以上用背景色填充指定矩形来达到清除矩形的效果。也就是说,当一个Graphics对象使用该方法时,相当于在使用一个“橡皮擦”。其中,参数x、y是被清除矩形的左上角的坐标,另外两个参数是被清除矩形的宽和高。 3.5Java 2D简介 3.5.1Java 2D API Java 2D API(Application Programming Interface)增强了抽象窗口工具包(AWT)的图形、文本和图像功能,可以创建高级图形库,开发更加强大的用户接口和新型的Java应用程序。Java 2D API对AWT进行了扩展,提供了更加灵活、功能更全面的绘制包,使其支持更多的图形绘制操作。 Java 2D是Java核心类库的一部分,它包含 java.awt、 java.awt.image、 java.awt.color、 java.awt.font、 java.awt.geom、 java.awt.print、 java.awt.image.renderable和 com.sun.image.codec.jpeg包。 其中,java.awt包中包含一般的或比原有类增强的Java 2D API类和接口; java.awt.image和java.awt.image.renderable包中包含用于图像定义与绘制的类和接口; java.awt.color包中包含用于颜色空间定义与颜色监视的类和接口; java.awt.font包中包含用于文本布局与字体定义的类和接口; java.awt.geom包中包含所有与几何图形定义相关的类和接口; java.awt.print包中包含用于打印所有基于Java 2D的文本、图形和图像的类和接口。 3.5.2Graphics2D简介 Graphics2D扩展了java.awt.Graphics包,使得对形状、文本和图像的控制更加完善。Graphics2D对象保存了大量用来确定如何绘制图形的信息,其中大部分包含在一个Graphics2D对象的6个属性之中,这6个属性如下。 (1) 绘制(Paint): 该属性确定所绘制线条的颜色以及填充图形的颜色和图案等。用户可以通过setPaint(Paint p)方法进行该属性的设置。 (2) 画笔(Stroke): 该属性可以确定线条的类型、粗细以及线段端点的形状。用户可以通过setStroke(Stroke s)方法进行该属性的设置。 (3) 字体(Font): 该属性可以确定所显示字符串的字体。用户可以通过setFont(Font f)方法进行该属性的设置。 (4) 转换(Transform): 该属性确定了图形绘制过程中要应用的转换方法,通过指定转换方法可以将绘制内容进行平移、旋转和缩放。用户可以通过setTransform()方法进行该属性的设置。 (5) 剪切(Clip): 该属性定义了组件上某区域的边界。用户可以通过setClip(Clip c)方法进行该属性的设置。 (6) 合成(Composite): 该属性定义了如何绘制重叠的几何图形,使用合成规则可以确定重叠区域的显示效果。用户可以通过setComposite(Composite c)方法设置该属性的值。 在一般情况下,使用Graphics2D对象的方法进行图形的绘制,Graphics2D对象的常用方法如下。 (1) abstract void clip(Shape s): 将当前Clip与指定Shape的内部区域相交,并将Clip设置为所得的交集。 (2) abstract void draw(Shape s): 使用当前Graphics2D上下文的设置绘制Shape的轮廓。 (3) abstract void drawImage(BufferedImage img, BufferedImageOp op, int x, int y): 呈现使用 BufferedImageOp 过滤的 BufferedImage 应用的呈现属性,包括 Clip、Transform 和 Composite 属性。 (4) abstract boolean drawImage(Image img, AffineTransform xform, ImageObserver obs): 呈现一个图像,在绘制前进行从图像空间到用户空间的转换。 (5) abstract void drawString(String s,float x,float y): 使用 Graphics2D上下文中的当前文本属性状态呈现由String指定的文本。 (6) abstract void drawString(String str, int x, int y): 使用Graphics2D上下文中的当前文本属性状态呈现由String指定的文本。 (7) abstract void fill(Shape s): 使用Graphics2D上下文的设置填充Shape的内部区域。 (8) abstract Color getBackground(): 返回用于清除区域的背景色。 (9) abstract Composite getComposite(): 返回 Graphics2D 上下文中的当前 Composite。 (10) abstract Paint getPaint(): 返回 Graphics2D 上下文中的当前 Paint。 (11) abstract Stroke getStroke(): 返回 Graphics2D 上下文中的当前 Stroke。 (12) abstract boolean hit(Rectangle rect, Shape s, boolean onStroke): 检查指定的 Shape 是否与设备空间中的指定 Rectangle 相交。 (13) abstract void rotate(double theta): 将当前的 Graphics2D Transform 与旋转转换连接。 (14) abstract void rotate(double theta, double x, double y): 将当前的 Graphics2D Transform 与平移后的旋转转换连接。 (15) abstract void scale(double sx, double sy): 将当前的Graphics2D Transform与可缩放转换连接。 (16) abstract void setBackground(Color color): 设置Graphics2D上下文的背景色。 (17) abstract void setComposite(Composite comp): 为 Graphics2D上下文设置 Composite,Composite 用于所有绘制方法中,例如 drawImage()、drawString()、draw() 和 fill(),它指定新的像素如何在呈现过程中与图形设备上的现有像素组合。 (18) abstract void setPaint(Paint paint): 为 Graphics2D 上下文设置 Paint 属性。 (19) abstract void setStroke(Stroke s): 为 Graphics2D 上下文设置 Stroke。 (20) abstract void setTransform(AffineTransform Tx): 重写Graphics2D上下文中的 Transform。 (21) abstract void shear(double shx, double shy): 将当前的Graphics2D Transform与剪裁转换连接。 (22) abstract void translate(double tx, double ty): 将当前的Graphics2D Transform与平移转换连接。 (23) abstract void translate(int x, int y): 将Graphics2D上下文的原点平移到当前坐标系统中的点 (x,y)。 3.5.3Graphics2D的图形绘制 Graphics2D是Graphics类的子类,它也是一个抽象类,不能实例化Graphics2D对象。为了使用Graphics2D,可以通过Graphics对象传递一个组件的绘制方法给Graphics2D对象,例如: public void paint(Graphics g){ Graphics2D g2=(Graphics 2D)g; … } Java 2D API提供了几种定义点、直线、曲线、矩形和椭圆等常用几何对象的类,这些新几何类是java.awt.geom包的组成部分,包括Point2D、Line2D、Arc2D、Rectangle2D和Ellipse2D等。每个类都有单精度和双精度两种像素定义方式,例如Point2D.double和Point2D.float、Line2D.double和Line2D.float等,使用这些类可以很容易地绘制基本的二维图形对象。 【例35】使用Graphics2D绘制直线、矩形和椭圆。程序源代码见Graphics2DDemo.java,程序运行结果如图311所示。 //Graphics2DDemo.java import java.awt.*; import javax.swing.*; import java.awt.geom.*; public class Graphics2DDemo extends JFrame{ public Graphics2DDemo() { super(); setTitle("Draw 2D Shape Demo"); setSize(300,200); setVisible(true); } public void paint(Graphics g) { //建立Graphics2D对象 Graphics2D g2=(Graphics2D) g ; //建立Line2D对象 Line2D l=new Line2D.Double(50,50,200,50); g2.draw(l); //建立Rectangle2D对象 Rectangle2D r=new Rectangle2D.Float(30,80,100,100); Color c=new Color(10,20,255); g2.setColor(c); g2.draw(r); //建立Ellipse2D对象 Ellipse2D e=new Ellipse2D.Double(150,80,100,100); g2.setColor(Color.GRAY); g2.fill(e); } public static void main(String[] args) { Graphics2DDemo g=new Graphics2DDemo(); g.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } } 图311例35的运行结果 3.5.4Graphics2D的属性设置 Graphics2D通过设置对象的属性来确定如何绘制图形的信息,在前面已经介绍了Graphics2D对象的6种属性,包括Paint、Stroke、Font、Transform、Clip和Composite。下面介绍如何在Graphics2D的图形上下文中设置常用的属性,即Paint、Stroke和Composite。 (1) Paint用于填充绘制图形的颜色或图案,在Java 2D API中提供了两种Paint属性的填充方式,即GradientPaint和TexturePaint。GradientPaint定义在两种颜色间渐变的填充方式,而TexturePaint利用重复图像片段定义一种纹理填充方式。用户可以使用setPaint()方法设置定义好的填充方式并将其应用于绘制的图形中。 GradientPaint类提供了下面的构造方法来建立颜色渐变方式: ① GradientPaint(float x1,float y1,Color color1,float x2,float y2,Color color2); ② GradientPaint(float x1,float y1,Color color1,float x2,float y2,Color color2,boolean cyclic); ③ GradientPaint(Point2D p1,Color color1,Point2D p2,Color color2); ④ GradientPaint(Point2D p1,Color color1,Point2D p2,Color color2,boolean cyclic)。 其中,构造方法①和②中的参数x1、y1指定颜色渐变的起点坐标,x2、y2指定颜色渐变的终点坐标,填充颜色从color1渐变至color2。当构造方法②中的参数cyclic为true时,填充方式和构造方法①定义的相同,若cyclic为false,则填充方式为非周期性渐变。构造方法③和构造方法①类似,构造方法④和构造方法②类似,只是在构造方法③和④中使用了Point2D对象来指定填充颜色渐变的起始(p1)和结束(p2)位置。 TexturePaint类的构造方法如下: TexturePaint(BufferedImage txtr,Rectangle2D anchor); 其中,txtr用来定义一个单位的填充图像的材质,anchor用来复制材质。 【例36】使用GradientPaint渐变填充方式和TexturePaint纹理填充方式绘制图形。程序源代码见PaintDemo.java,程序运行结果如图312所示,使用纹理填充方式绘制图形的填充单元图像如图313所示。 //PaintDemo.java import java.awt.*; import java.awt.geom.*; import java.awt.image.BufferedImage; import javax.swing.*; public class PaintDemo extends JFrame{ public PaintDemo() { super(); setTitle("Paint Demo"); setSize(300,200); setVisible(true); } public void paint(Graphics g) { Graphics2D g2=(Graphics2D) g; //建立Point2D对象p1、p2,将它们作为颜色渐变的起点和终点 Point2D p1=new Point2D.Double(70,70); Point2D p2=new Point2D.Double(90,90); GradientPaint gp=new GradientPaint(p1,Color.white,p2,Color.black,true); Ellipse2D e1=new Ellipse2D.Double(30,60,90,90); g2.setPaint(gp); //设置画笔绘制方式 g2.fill(e1); //建立用于填充图形的一个单位的材质 BufferedImage bi=new BufferedImage(10,10,BufferedImage.TYPE_INT_RGB); Graphics2D bg=bi.createGraphics(); bg.setColor(Color.white); bg.fillRect(0,0,10,10); bg.setColor(Color.red); bg.fillRect(0,0,5,5); bg.fillRect(5,5,5,5); Rectangle2D r1=new Rectangle2D.Double(0,0,10,10); //设置复制填充材质的区域 Ellipse2D e2=new Ellipse2D.Double(150,60,90,90);//创建需要绘制的图形 TexturePaint tp=new TexturePaint(bi,r1);//设置填充方式 g2.setPaint(tp);//设置绘制方式 g2.fill(e2); } public static void main(String[] args) { PaintDemo p=new PaintDemo(); p.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } } 图312例36的运行结果 图313用于填充图形的单元图像 (2) Stroke用于在绘制图形的轮廓时确定线条的形状和粗细,通常使用BasicStroke对象来定义,通过setStroke()方法设定Stroke属性的值。BasicStroke定义的特性包括线条宽度、笔形样式、线段连接样式和点画线图案等。在使用Stroke属性设定图形轮廓的绘制方式时,首先调用setStroke()方法设定轮廓的绘制方式,然后使用setPaint()方法定义画笔如何绘制该图形,最后使用draw()方法绘制该图形。 在BasicStroke中定义了一组基本的简单图形轮廓的直线绘制和点画线绘制方式,它提供了3种绘制粗线的末端样式,即CAP_BUTT、CAP_ROUND和CAP_SQUARE,以及3种线段连接样式,即JOIN_BEVEL、JOIN_MITER和JOIN_ROUND。 BasicStroke类提供了下面的构造方法来建立画笔的绘制方式: ① BasicStroke(); ② BasicStroke(float width); ③ BasicStroke(float width,int cap,int join); ④ BasicStroke(float width,int cap,int join,float minterlimit); ⑤ BasicStroke(float width,int cap,int join,float minterlimit,float[] dash,float dash_phase)。 其中,width表示轮廓线的宽度; cap表示轮廓线末端的样式; join表示相交线段的连接样式; minterlimit表示在JOIN_MITER模式下若相交的尖形末端大于minterlimit,则超过部分被削去; dash为虚线的样式,数组内的值为点画线和空白间距的值; dash_phase为虚线样式数组的起始索引。 【例37】使用BasicStroke类设定画笔的绘制方式。程序源代码见StrokeDemo.java,程序运行结果如图314所示。 //StrokeDemo.java import java.awt.*; import javax.swing.*; import java.awt.geom.*; public class StrokeDemo extends JFrame{ public StrokeDemo() { super(); setTitle("Stroke Demo"); setSize(300,200); setVisible(true); } public void paint(Graphics g) { Graphics2D g2=(Graphics2D) g ; Line2D l=new Line2D.Double(30,50,100,80); //创建一个BasicStroke对象来设置直线的绘制方式 Stroke stroke=new BasicStroke(10.0f, BasicStroke.CAP_ROUND,BasicStroke.JOIN_BEVEL); g2.setStroke(stroke); g2.draw(l); Ellipse2D e=new Ellipse2D.Double(150,50,90,90); //创建一个BasicStroke对象来设置椭圆的绘制方式 stroke=new BasicStroke(8,BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL,0,new float[] { 10,5 },0); g2.setStroke(stroke); g2.draw(e); Rectangle2D r=new Rectangle2D.Double(30,100,80,80); //创建一个BasicStroke对象来设置矩形的绘制方式 stroke=new BasicStroke(10,BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND,0); g2.setStroke(stroke); g2.draw(r); } public static void main(String[] args) { StrokeDemo s=new StrokeDemo(); s.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } } 图314例37的运行结果 (3) Composite用于定义重叠图形的绘制方式。在绘制多个图形时,若遇到图形重叠的情况,需要确定重叠部分的颜色显示方式,重叠区域的像素颜色决定了该部分图形的透明程度。在Composite的定义中,最常用的就是AlphaComposite,可以通过setComposite()方法将AlphaComposite对象添加到Graphics2D上下文中,设置图形重叠部分的复合样式。在AlphaComposite类中定义了多种新颜色与已有颜色的复合规则,例如SRC_OVER表示混合时新颜色(源色)覆盖在已有颜色(目标色)之上; DST_OUT表示混合时去除已有颜色; SRC_OUT表示混合时去除新颜色; DST_OVER表示混合时用已有颜色覆盖新颜色。在设置混合颜色的同时还可以设置颜色的alpha值,它用百分比表示在颜色重叠时当前颜色的透明度,alpha值为0.0(完全透明)~1.0(完全不透明)。 3.5.5路径类 在java.awt.geom包中定义了几何图形类,包括点、直线、矩形、圆、椭圆、多边形等。该包中各类的层次结构如下: |- java.lang.Object |- java.awt.geom.AffineTransform |- java.awt.geom.Area |- java.awt.geom.CubicCurve2D |- java.awt.geom.CubicCurve2D.Double |- java.awt.geom.CubicCurve2D.Float |- java.awt.geom.Dimension2D |- java.awt.geom.FlatteningPathIterator |- java.awt.geom.Line2D |- java.awt.geom.Line2D.Double |- java.awt.geom.Line2D.Float |- java.awt.geom.Path2D |- java.awt.geom.Path2D.Double |- java.awt.geom.Path2D.Float |- java.awt.geom.GeneralPath |- java.awt.geom.Point2D |- java.awt.geom.Point2D.Double |- java.awt.geom.Point2D.Float |- java.awt.geom.QuadCurve2D |- java.awt.geom.QuadCurve2D.Double |- java.awt.geom.QuadCurve2D.Float |- java.awt.geom.RectangularShape |- java.awt.geom.Arc2D |- java.awt.geom.Arc2D.Double |- java.awt.geom.Arc2D.Float |- java.awt.geom.Ellipse2D |- java.awt.geom.Ellipse2D.Double |- java.awt.geom.Ellipse2D.Float |- java.awt.geom.Rectangle2D 路径类用于构造直线、二次曲线和三次曲线的几何路径,它可以包含多个子路径。如上面的类层次结构所描述,Path2D是基类(它是一个抽象类),Path2D.Double和Path2D.Float 是其子类,它们分别以不同精度的坐标定义几何路径。在Java 1.5及以前的版本中,GeneralPath是一个独立的最终类,在1.6版本中进行了调整与划分,其功能由Path2D替代,为了兼容,把它划分为Path2D.Float派生的最终类。下面以GeneralPath类为例介绍路径类的功能与应用。 1. 构造方法 构造路径对象的方法如下。 (1) GeneralPath(int rule): 以rule指定的缠绕规则构建对象。缠绕规则确定路径内部的方式,缠绕规则有两种,其中Path2D.WIND_EVEN_ODD用于确定路径内部的奇偶 (evenodd) 缠绕规则,Path2D.WIND_NON_ZERO用于确定路径内部的非零 (nonzero)缠绕规则。 (2) GeneralPath(): 以默认的缠绕规则Path2D.WIND_NON_ZERO构建对象。 (3) GeneralPath(int rule, int initialCapacity): 以rule指定的缠绕规则和initialCapacity指定的容量(以存储路径坐标)构建对象。 (4) GeneralPath(Shape s): 以Shape对象s构建对象。 2. 常用方法 路径对象的常用方法如下。 (1) void append(Shape s, boolean connect): 将指定Shape对象的几何形状追加到路径中,也许使用一条线段将新几何形状连接到现有的路径段。如果connect为true,并且路径非空,则被追加的Shape几何形状的初始moveTo操作将被转换为lineTo操作。 (2) void closePath(): 回到初始点,使之形成闭合的路径。 (3) boolean contains(double x, double y): 测试指定坐标是否在当前绘制边界内。 (4) void curveTo(float x1, float y1, float x2, float y2, float x3, float y3): 将3个新点定义的曲线段添加到路径中。 (5) Rectangle2D getBounds2D(): 获得路径的边界框。 (6) Point2D getCurrentPoint(): 获得当前添加到路径的坐标。 (7) int getWindingRule(): 获得缠绕规则。 (8) void lineTo(float x, float y): 绘制一条从当前坐标到(x,y)指定坐标的直线,将(x,y)坐标添加到路径中。 (9) void moveTo(float x, float y): 从当前坐标位置移动到(x,y)指定位置,将(x,y)坐标添加到路径中。 (10) void quadTo(float x1, float y1, float x2, float y2): 将两个新点定义的曲线段添加到路径中。 (11) void reset(): 将路径重置为空。 (12) void setWindingRule(int rule): 设置缠绕规则。 (13) void transform(AffineTransform at): 使用指定的AffineTransform 变换此路径的几何形状。 【例38】使用GeneralPath类绘制一个正三角形和一个倒三角形。程序源代码见AddPathExample.java,程序运行结果如图315所示。 //AddPathExample.java import java.awt.*; import java.awt.geom.*; import javax.swing.JFrame; public class AddPathExample extends JFrame{ public AddPathExample() { super(); setTitle("GeneralPath Demo"); setSize(200,200); setVisible(true); } public void paint(Graphics g) { Graphics2D g2 = (Graphics2D) g; GeneralPath myPath, myPath2; // myArray包含正三角形的所有顶点 Point[] myArray = { new Point(130,130), new Point(160,160), new Point(100,160), new Point(130,130) }; myPath = new GeneralPath();//建立GeneralPath对象 myPath.moveTo(myArray[0].x, myArray[0].y);//起始顶点 for(int i=1; i