java.awt包的Window类

一个窗体对象是一个(top-level)窗体,该窗体没有边框和菜单条;该窗体的默认的布局方式是BorderLayout方式。一个窗体对象必须拥有一个frame,或者Dialog或者另外一个窗体对象。窗体对象概念如下图所示:

Java游戏编程之重要API_游戏开发

在多屏幕环境中,我们可这样的构造方法Window(Window, GraphicsConfiguration)在不同的屏幕设备(screen device)中创建一个窗体对象。 GraphicsConfiguration对象表示的上目标屏幕设备。在一个虚拟设备的多屏幕环境中,桌面区域可以跨多个物理屏幕设备,所有设备的边界是相对于虚拟设备坐标系统的(参见上图)。虚拟坐标系统的原坐标要高于主要物理屏幕的左上角坐标。然后窗体根据虚拟设备中的主屏幕的坐标来定位。

在这种环境下,当我们呼叫一个setLocation方法时,必须给该方法传送一个虚拟坐标值。同样,当我们使用getLocationOnScreen方法,窗体对象会返回一个虚拟设备的坐标值。当我们呼叫GraphicsConfiguration类的getBounds方法时,我们会虚拟坐标系统中的源点值。下面的代码是设置一个窗体在(10,10)位置,该位置相对于物理屏幕的源点的位置。如果GraphicsConfiguration的边界没有越界,那么该窗体会被设置为(10,10),而该值是虚拟坐标值,所以它会出现主要物理屏幕中。

该坐标值不等于指定的GraphicsConfiguration对象的物理屏幕的值。示例代码如下:

Window w = new Window(Window owner, GraphicsConfiguration gc);
Rectangle bounds = gc.getBounds();
w.setLocation(10 + bounds.x, 10 + bounds.y);

注意:窗体(包含Windows, Frames和Dialogs)的位置和大小是由操作系统的桌面的窗体管理系统来控制的。也就是说,我们呼叫setLocation、setSize和setBounds方法时,是我们向视窗操作系统的窗体管理系统发送请求(当然是间接间接的)。

但是在某些情况下,窗体管理系统可能会忽略这样的请求,或者修改这些几何请求,以便能够放到合适位置,从而能够接近操作系统中桌面设置的要求。因为有操作系统本地的事件处理是异步的原因,所以getBounds、getLocation、getSize和getLocationOnScreen返回的结果可能不会是屏幕上Window的实际几何值,除非所有的请求都处理完毕了。这是因为窗体管理系统在处理这些子请求修改相应的请求数据所造成的。比如我们可缩放应用窗体的大小,而相应的窗体管理系统会随时调整窗体的显示大小值。对于这样调整的结果,一般会产生多个ComponentEvent事件对象,以表示新的几何图形。Window可以产生以下事件:

  • WindowOpen
  • WindowClosed
  • WindowGainedFocus
  • WindowLostFocus

该类创建自JDK 1.0版本。

java.awt包的Graphics2D类

该类继承Graphics类,但是提供了更复杂的控制、坐标转换、颜色管理和文本布局。该类是呈现二维空间、文本和图片的基本类。

坐标空间—所有传送给Graphics2D对象的坐标都是在独立坐标系统中指定的,该系统叫做User Space,该空间是由应用使用的。该类包含AffineTransform对象,用来呈现状态的一部分,该类定义了怎样转换用户坐标为Device Space的设备依赖的坐标。

设备空间的坐标通常引用独立设备像素,然后在这些像素之间进行排序填充,以消除这些gap值。一些Graphics2D对象可以被用来捕获呈现操作,然后保存图形metafile文件,以便未知的物理设备上回放。因为这种解决方案不为人所,所以Graphics2D实现把用户坐标转换成虚拟空间坐标。每个Graphics2D对象都关联一个目标,该目标就是呈现的地方。GraphicsConfiguration对象定义了呈现目标的性质,比如像素格式和解决方案。在Graphics2D对象生命周期中使用相同的呈现目标。当创建一个Graphics2D对象时,GraphicsConfiguration指定一个默认的转换给Graphics2D对象的目标对象,比如Component或者Image对象。这个默认的转换影射用户空坐标系统到屏幕或者打印机设备的坐标系统,其中X增加表示坐标水平右移,如果Y增加表示重直向下移。屏幕默认的转换单元是72 dpi(像素值)。打印是每英寸72像素值。对于图形缓存,也使用相同的转换单元。

呈现处理过程—该过程被分为四个阶段, 目标是由Graphics2D呈现属性来控制的。呈现器可以通过更多的步骤来优化,不管是缓存结果,以便于后面呼叫时使用,也可以把一个操作分解成多个虚拟步骤。其呈现处理过程如下:

  • 决定呈现什么
  • 约束呈现操作到当前的clip. 所谓Clip是在用户空间中通过一个Shape指定的,并且被程序所控制。程序使用Graphics和Graphics2d类的clip操作方法来呈现。这种user clip通过Transform对象被转换到设备空间。设备空间使用device clip与user clip组成一个composite clip以最终决定最后的clipping区。User clip不会被呈现系统的所修改,而只会被composite clip所影射。
  • 决定什么颜色被呈现
  • 根据Graphics2D上下文的当前的Composite属性,把颜色作用到目标绘制界面。

呈现操作有三种,每种操作都自己的呈现处理过程。

  • Shape operations (形状操作)
    • 如果操作是一个画(shape)操作,那么呼叫方法createStokedShape来构建一个新的形状对象,该对象包含指定Shape的外形。
    • 该形状从user space转换到device space的形状,转换时使用Graphics2d上下文的当前Transform对象。
    • 该形状的外形是使用Shape的方法getPathIterator抽取出来,该方法返回一个PathIterator对象,该对象根据Shape的边界进行迭代。
    • 如果Graphics2D对象不能处理PathIterator曲形段,然后呼叫Shape的getPathIterator方法。
    • 在Graphics2D上下文中当前Paint需要PaintContext对象,该上下文对象指定设备空间中的颜色呈现
  • Text operations (文本操作)
    • 下面的步骤用来决定所需的字形(glyph)来呈现指定的字符串:
    • 如果参照是一个字符串,那么在Graphics2D上下文中的当前Font对象被要求转换字符串的Unicode字符为一组字形,以便与基本布局和字符实现的形状算法起呈现具体的字形。
    • 如果参见是一个AttributedCharacterIterator对象,那么该迭代器对象会被要求转换它自己到TextLayout对象,转换时使用它内置的字体属性。TextLayout对象实现了复杂的字形布局算法,该算法使用Unicode双向布局自动调整多种字体。
    • 如果参见是GlyphVector对象,那么该对象已经包含了相应的指定字体字形代码,该代码有每个字形的位置坐标值。
    • 当前Font对象需要获取指定字形的外形,这些外形在user space中被看成形状。
    • 根据以上的Shape操作,字符外形被填充到指定的字形上
    • 在PaintContext对象中呼叫当前的Paint对象,以便指定device space中的颜色来呈现。
  • Image Operations (图形)
    • 源Image的bounding box定义了交集区域,在Image Space中该bounding box是被指定的,也就是Image对象的本地坐标系统
    • 如果AffineTransform被传送到drawImage方法,AffineTransform对象被用来从image space转换到user space中去。如果没有AffineTransform对象,那么bounding box被认为已经存在于user space中了。
    • 然后源Image的bounding box从user space转换到device space中去,转换时使用当前的Transform对象。注意,在device space的矩形区域中是不会有转换动作的。
    • Image对象决定哪种颜色被呈现,然后根据源和目的坐标影射到指定的当前的Transform对象中去,以及优化的image转换。

Default Rendering Attributes—Graphics2D呈现属性默认值:

  • Paint—Component的颜色Font—Component的字体
  • Stoke—一个方形的笔
  • Transform—Component的GraphicsConfiguration对象的getDefaultTransform方法的返回对象
  • Composite—表示AlphaComposite.SRC_OVER规则Clip—没有呈现Clip时,那么是该Component的输出的clip值。

呈现兼容性问题—JDK 1.1呈现模型是基于像素模型,该模型指定坐标是无穷小的,也就是像素之间的填充。绘制操作是使用一个像素宽度的笔来绘制实现的,该笔填一个一个根据绘制路径填充像素到一个指定的锚点。JDK 1.1呈现模式是由大多数现有被平台用来呈现的类组成,这些类需要把整数坐标转换成离散的笔来完成指定的像素。Java 2D API支持拒锯齿呈现技术,一只笔使用一个像素不能完全支持N和N+1的落差现象,所以如果设置的抗锯齿功能,那么呈现器会决定使用哪个

像素来填补两个像素之间的落差。Java 2D API维护JDK呈现行为的兼容性问题,比如原有的legacy操作和已存的呈现行为不会在Java 2D API中修改。Legacy方法影射既定了的通用的绘制和填充方法,这些方法清楚的标识了Graphics2D怎样继承Graphic基类,该类基于Stroke和Transform属性。有限的执行步骤是默认的属性设备,比如默认的Stroke是BasicStroke类,它是一个1值没有虚线,并且默认提Transform给屏幕绘制的唯一传输对象。

下面是锯齿和反锯齿预呈现行为规则:

  • 设备坐标被定义到device像素之间,以避免产生锯齿的反锯齿呈现的不一致性。如果坐标被定义在一个像素的中间,那么该像素的一些部分会被一个形状所覆盖,比如矩形只有一半被覆盖。当使用锯齿呈现时,覆盖一半的像素可以shape的内部或者外部。当使用抗锯齿呈现时,整个shape的边界像素会有一半被覆盖。另一方面,因为坐标在像素之间被定义,所以一个shape像矩形不会有一半被覆盖,不管它是否被使用抗锯齿呈现。Line和路径使用BasicStoke对象可以被“normalized”(标准化)之后,可以提供outline的呈现一致性,标准化(normalization)过程是通过KEY_STROKE_CONTROL来控制。而抽象标准化算法不是指定的,但是它的目标是确保line是可视化的一致性。 下列是所有legacy方法是基于默认的属性设置: 填充操作,包括fillRect, fillRoundRect, fillOval, fillArc, fillPolygon和clearRect. 比如 fill(new Rectangle(x, y, w, h));
  • 同样绘制操作,包括drawLine, drawRect, drawRoundRect, drawOval, drawArc, drawPolyline和drawPolygon. draw(new Rectangle(x, y, w, h));
  • 方法draw3DRect和fill3DRect方法实现了Graphics类的drawLine和fillRect方法。这些方法预定义了它们的行为,定义时是根据Graphics2D上下文中的当前Stroke和Paint对象的来确定的。它重写了当前Paint对象,并且使用fillRect来描述相同的抽象行为。Graphics类只定义了setColor方法来控制喷绘的颜色。而在Java 2D API包中扩展了Color对象的,并且实现了新的Paint接口,现存的setColor方法是为了方便设置当前Paint属性的到一个Color对象,setColor方法等同setPaint方法。其中类Graphics定义了两个方法来控制颜色怎样被应用到目标中去。
    • setPaintMode方法实现设置默认的组件,等同于setComposite (new AlphaComposite)方法
    • setXORMode(Color xorColor)方法用来方便设置一个固定的Composite对象,而忽略Alpha源颜色

组件和设置目标颜色为值:

dstpixel = (PixelOf(scrColor) ^ PixelOf(xorColor) ^ dstpixel);
总结

Java给我们第三方程序提供了大量的API来方便开发,因此,当我们使用Java编程开发时,必然有一个默认习惯:根据自己的开发技术需求,先认真看API可以给我们提供什么,并且认真阅读这些API的功能描述。


图片来源:http://www.lyouxi.com/  手游