技术开发 频道

创建用于翻转效果的 Java2D 合成

  RolloverComposite 必须实现 java.awt.Composite 接口。这个类有一个单独的 Entry Helpers 方法,该方法返回 java.awt.CompositeContext 的实例。RolloverComposite 不负责对图形表面上的像素的实际图元进行操作,而是把这项任务委托给能够在多线程环境中维护状态和工作的合成上下文对象,因为针对单个合成可以存在多个合成上下文对象。

  ColorModel 抽象类具有能在颜色组件和基本的红、绿、蓝以及 alpha 组件之间进行转换的 API。 RenderingHints 是来自 Graphics2D 的着色提示,RolloverComposite 在需要时可以使用它,例如,在进行文本着色时是否要使用抗锯齿,或者应该使用什么类型的行合并样式。 CompositeContext 是实际操作原始像素的线程安全的对象,我们将创建一个实现这个目的的匿名内部类,如下所示:

1        // Get the source pixels
2             int[] srcPixels = new int[4];
3             src.getPixel(x,y,srcPixels);
4             // Ignore transparent pixels
5             if (srcPixels[3] != 0){
6                 // Lighten each color by 1/2, and increasing the blue
7                 srcPixels[0] = srcPixels[0] / 2;
8                 srcPixels[1] = srcPixels[1] / 2;
9                 srcPixels[2] = srcPixels[2] / 2 + 68;
10                 dstOut.setPixel(x,y,srcPixels);
11             }
12         }
13     };
14 }
15

 

  CompositeContext 接口有两个方法,即 dispose() 和 compose(Raster,Raster,WritableRaster) 。dispose 方法让我们清除任何已经分配的资源,而 compose 方法则负责图元绘图的方法。我们没有任何需要清除的对象,所以可以有一个 dispose() 的不进行任何操作的实现, compose(...) 方法则是我们对像素进行操作的地方。

  compose(...) 方法的三个参数是,用于源图像的 Raster、用于目标图像的 Raster 以及表示图形表面上将被着色的输出的 WritableRaster 。要访问给定位置的原始像素,可以使用 getPixel(int x, int y, pixel int[]) 方法。int[] 参数是一个由四个参数组成的数组,表示像素的红、绿、蓝以及 alpha 值。src 参数包含源参数的光栅, dstOut 参数则是具有 setPixel(int x, int y, pixel int[]) 方法的 WritableRaster。通过反复操作来自源图像的每个像素,我们就可以创建具有完成操作后的值的新像素,并将它设置到 dstOut 中,这个 dstOut 将被绘制到图形表面上。compose 方法的代码如下所示:

  请注意,我们检查了第四个像素 (srcPixels[3]) ,看看它是不是透明的。如果它在源图像上时是透明的,则我们就不写任何内容到 dstOut 中,因为我们想让绘图表面现有的像素保持不变。

  完成代码

  创建了返回 CompositeContext (它负责把所期望的像素值设置到要被绘制到图形表面上的光栅中)的 RolloverComposite 类之后,我们需要在 RolloverIcon 类中完成代码。早些时候我们在测试异或合成时,我们要在通过 paintIcon(...) 方法将它设置到图形的 composite 中之前先创建一个新实例。在 Java 语言中,创建对象的开销很大,因为必须分配内存,然后在不再需要时对所得到的对象进行垃圾回收,所以,我们将改用可以根据需要进行重用的 RolloverComposite 类的单子(singleton)实例。我们不必担心多个图标或图形对象会具有对同一个对象的访问权,因为所有的状态都由 CompositeContext 保存,CompositeContext 可以根据需要重新创建并能够提供线程安全的访问。

  RolloverComposite 将在叫做 DEFAULT 的公共静态(public static)域包含它的单个实例。为了迫使人们使用这个单子实例(singleton)而不是每次创建一个新对象,构造函数被声明成私有的(private),这样便只有 RolloverComposite 类能够创建它自己的实例。

1 public class RolloverComposite implements Composite {
2   public static RolloverComposite DEFAULT = new RolloverComposite();
3   private RolloverComposite(){ }
4

 

  RolloverIcon 的 paintIcon 方法在绘制它包装的初始图标之前需要将图形参数的 composite 设置成单子 RolloverComposite 。绘制完成后需要恢复原来的 composite,以确保随后的任何绘图操作不会受到由让定制的 composite 实例保留超过所需要的时间所带来的不必要影响。

1 public void paintIcon(Component c, Graphics g, int x, int y) {
2   Graphics2D g2D = (Graphics2D)g;
3   Composite oldComposite = g2D.getComposite();
4   g2D.setComposite(RolloverComposite.DEFAULT);
5   fIcon.paintIcon(c,g,x,y);
6   g2D.setComposite(oldComposite);
7 }
8

 

  完成的结果

  编写完 RolloverIcon 类的代码后,现在我们需要测试它。为此,我们编写了一个测试工具,它创建两行按钮,每行有四个,其中上面那行具有翻转效果,下面那行按钮的图标被永久性地设置成翻转图标。您可以从下面的 参考资料部分下载这个测试工具的代码以及 RolloverIcon 和 RolloverComposite 类的所有代码。

  图 3. 测试工具显示了 RolloverIcon 的效果。

  结束语

  RolloverIcon 是 Java2D API 的可扩展性有多么好的一个示例,这样我们便可以访问图形子系统中级别很低的组件,从而创建我们自己的扩展。对图形对象所使用的合成进行控制是我们用来很好地实现图形效果的办法,但对 Java2D 的工作机制有了更深的理解后,我们还可以实现许多其它的定制效果。

0
相关文章