在第11章中,我们看到了计算机屏幕拥有坐标系统,它被用来定义窗口的位置和尺寸。我们还看到了如何把组件添加到容器中。布局管理器创建的位置上。这个坐标系统类似屏幕坐标系统。原点在容器的左上角,x轴的水平方向从左向右,Y轴从上到下。 JWirindow或JFrame对象中的按钮位置用一对(x,y)像素坐标指定。这个坐标相对于屏幕上容器对象的左上角原点。下面你可以看到Stetcher应用程序窗口的坐标系统。
当然,对于窗口对象,窗口的层级窗格拥有自己的坐标系统,其原点在窗格的左上角。这个坐标系用来决定菜单和内容窗格的位置。内容窗格也拥有自己的坐标系统。它被用来决定它所包含的组件位置。
不只是容器和窗口拥有自己的坐标系统,每个JButton对象也有自己的系统,比如JToolbar对象。实际上每个组件都拥有自己的坐标系统。
很清楚,容器为了指定它所包含的组件位置需要一个坐标系统。你也需要一个坐标系统来绘制组件。例如,绘制一条直线。你需要能够指定组件相关的起始位置和结束位置,这里的坐标系统类似于容器中放置组件所应用的坐标系统,但并不完全一样。在绘图时显得要复杂些。比我们看一看在绘图时坐标系统是如何制定的。
Graphics2D类是从Graphics类派生来的,它定义了Java早期版本的设备环境。因此如果你希望使用旧的绘制方法,就继承Graphics2D类中的所有内容。但是,我们将注重Graphics2D提供的新的更加强大和更加灵活的功能。正像你将要看到的,图形设备环境的引用通常作为Graphic2D类型传递,因此你需要知道它。注意,Graphics和Graphics2D这两个类是抽象类,你不能直接地建立这两种类的对象。描述图形设备环境的对象完全取决于与之相关的组件,因此,为使用特定的组件,常常要获取图形设备环境。
组件的Graphics2D对象要将用户坐标镜像到设各坐标,因此,除了组件的用户坐标之外,它还包含了有关输出的目标设备的信息。把用户坐标转换成设各坐标所需信息被包含在三种不同类型的对象中:
GraphicsEnvirnment对象囊括了所有的图形设备(像GraphicsDevice对象)和你的计算机可用的字体(像Font对象).
GraphicsDevice对象囊括了有关屏幕或打印机这些特定设各的信息,并存储在一个或多个GraphicsConfiguration对象中。
GraphicsConfiguration对象定义了屏幕或打印机这样的特定设备的特性。显示器屏幕可有几个GraphicsConfiguration对象与之关联,每个GraphicaConfiguration对应一个特定的屏幕分辨率和可显示的颜色数组合。
图形设备环境还维护着绘图操作所需要的其他信息,如绘图颜色、线型以及对几个图形填充的颜色和图案。我们将在木章稍后的例子中看到如何利用这些属性进行操作。
由于图形设备环境为特定的组件定义了绘制内容,所以在你绘制组件之前,必须引用它的图形设备环境对象。通常,在需要重新构造组件时,你要调用实现的paint()方法绘制组件。描述组件的图形设备环境的对象要作为自变量传递给paint()方法,你可以使用这个图形设备环境绘制组件。图形设各环境包含用来绘制组件的所有方法。我们将在本章中讨论其中的一些方法。
paint()方法不是惟一的绘制组件的方法。你可以在任何时候调用getGraphics()方法为组件获取图形设备环境。
有这样一种情况,在你重新绘制组件时,希望避免直接地调用paint()方法。此时你就应该为组件调用repaint()这个方法有5个版本可供你使用。我们将查看其中的4个;
你将会发现,第一个或者最后一个方法是你使用最频繁的一个。
到现在为止,全部是理沦,下面花点时间实践一下。
让我们想像一下,应该如何利用添加到Sketcher的SkctchView对象在一个组件上绘制图形。我们需要做的全部工作是在SketchView类中实现paint()方法。
把下列方法的实现添加到SketchVicw类中:
import javax.swing.*;
import java.util.*; // For Observer
import java.awt.*; // For Graphics
class SketchView extends JComponent
implements Observer
{
public void paint(Graphics g)
{
// Temporary code
Graphics2D g2D = (Graphics2D)g; // Get a Java 2D device context
g2D.setPaint(Color.red); // Draw in red
g2D.draw3DRect(50, 50, 150, 100, true); // Draw a raised 3D rectangle
g2D.drawString("A nice 3D rectangle", 60, 100); // Draw some text
}
// Rest of the constractor as before…
}
如果你重新编译文件SketchFrame.java,并且运行Sketcher,就可以看到paint()方法产生的结果。你应该看到显示的窗口。
如何工作
图形设备环境作为Garphics类型(Graphics2D的基类)的自变量传递给paint()方法。因此,要使用定义在Grapics2D类中的方法,就必须首先转换成Graphica2D类型。paint()方法出于兼容的考虑有一个Graphics类型的自变量。
一旦转换了图形设备环境,我们就可以立即调用Graphic2D对象的setpaint()方法设置将要绘制的颜色,并且把绘图颜色作为自变量传递,此后的所有绘图操作都用Color.red当我们想绘制不同的颜色时,可以再次调用setpaint()改变颜色。下一步,我们调用定义在Graphics2D类中的draw3DRect()方法绘制一个三维矩形。前两个自变量是整型,用来指定绘制的矩形左仁角的x和y坐标,它相关于组件的用户空间原点,本例中是内容窗格中视图对象的左上角。第3, 4个自变量分别是矩形的宽度和高度,也是相对于用户坐标系。
drawstring()方法在第2、3个自变量指定的位置上绘制第一个自变量指出的字符串。这里的位置是指字符串第一个字母左下角在用户坐标系中的x和y坐标。字竹串将用设备环境中当前Font对象获取的字型绘制字符串,林的相应字符。正像我们生讨论Font对象时所看到的,字体的字型定义字符的物理外观。
但是有关绘图的内容要比这个例子中所介绍的多得多。图形设备环境除了使用的字体外,还有绘制的线型以及颜色等很多信息尸。让我们深入挖掘,继续仔细地看看还有些什么。
绘制过程
Graphics2D对象维护着决定如何绘图的一套完整的信息。大多数信息包含在Graphics2D对象内的6个属性中:
着色(paint)属性将决定绘制直线的颜色。它还定义用来填充几何图形的颜色和图案。着色属性可调用图形设备环境的SetPaint(Paint paint)方法设置。默认的着色属性是组件的颜色。
笔画(stroke)属性将定义决定线型的笔(Open).比如,实心、刷或点线以及线的粗细,它还决定直线端点的形状。笔画属性可调用图形设备环境的setStroke(Strokes)方法设置。默认的笔画属性定义一个正方形笔,它用一个用户坐标系单位的粗度绘制实心线。直线的端点是正方形,并且连接处被斜接。
字体〔font)属性将决定绘制文本时所使用的字体。字体属性可调用图形设备环境的setFont(Font font)方法设置。默认字体是组件设置的字体。
变换(transform)属性将定义在绘制处理中应用的变换。实际土当前的变换将决定所绘制内容的平移、旋转和缩放。正像我们将着到的,有几种对绘制的内容实施变换的方法。默认变换是保持内容不变的标识变换。
裁剪(clip)属性将定义组件区域的边界。着色操作被限制,以至于绘图只发生在裁剪边界的封闭区域内。裁剪属性可调用图形设备环境的两个SetClip()方法中其中一个进行设置。默认的裁剪属性是组件的全部区域。
组合Ccomposite)属性将决定被覆盖的几何图形如何在组件上绘制。你可以改变一个几何图形的填充颜色的透明度,因此,底层的几何图形可以透过来。你可用图形设备环境的setComposite(Composite comp)方法设置组合属性。默认的组合属性导致绘制的新几何图形在己经显示在那儿的内容之上,还要考虑所使用的颜色透明度。
描述属性的所有对象都以引用的形式存储在Grapttics2D对象内,因此,你必须经常调用setxxx()方法来改变图形设备环境中的属性,而不要直接从外部修改对象。如果你这样做,结果将是不可预料的。
在绘制直线是,你还可以用"锯齿"(jaggies)影响绘制过程的处理。在斜线上消除"锯齿"的过程叫做消除阶梯(antiaLiasing).我们对此问题不做更深入地研究。
有关属性还有大量的细节内容,我们不打算在此研究所有这些内容,我们将逐步探讨与我们创建的例子有关的新属性如何应用于图形设备环境。
绘制操作
为了绘制各种类的实体。Graphics2D对象提供了两种可用的基本方法。
让我们查看一下可用的集合吗图形,这将有助于Sketcher用途更广泛。