技术开发 频道

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

  【IT168 技术文章】

         引言

  许多应用程序都有包含图标的按钮,当按钮被选中或者鼠标移到按钮上时,按钮的图标会发生改变。Web 浏览器(如 Microsoft Internet Explorer)中的工具栏按钮就是这种现象的一个示例,其中的按钮图形是灰色的,当鼠标移动到按钮上时,图形会变成有颜色的。为了实现这种效果,要创建两组图形;一组用于正常状态,一组用于当鼠标移动到按钮上时的活动状态。然而,对于设计者来说,创建两组图形很费时间,并且意味着在需要更改图形时,必须对这两组图形做双倍的维护工作。更优化的办法是只使用一个图标,而图形效果则通过编程来实现,从而避免创建和维护一个单独图标的开销。本文描述的问题是针对如 图 1所示的向导页中的一组按钮的,当用户在每个按钮上悬停时,图形会发生改变以向用户表示该按钮是活动的。

  图 1.Web Module 按钮在鼠标移动到它上面时处于活动状态并且图形已经改变。

  在本文中,我们将说明如何通过使用 Java2D API 创建一个能够接受图像并创建所期望的效果的类来实现上述效果。这需要我们理解如何构造图像以及如何使用 AWT composite 来操作这些图像。

  背景知识

  javax.swing.JButton 类有一个布尔属性 rolloverEnabled 和一个 rolloverIcon 属性,后者的类型是 javax.swing.Icon。如果 rolloverEnabled 为 true,则当鼠标移动到按钮上时,rolloverIcon 的值就被用到该按钮的图形上。我们认定,一个优秀的解决方案应该有一个新的称为 RolloverImageIcon 的类,我们将在其构造函数中给它提供一张图像,然后,这个类会在绘制图标之前对图标进行操作。

  这样,用于创建 rolloverButton 的代码将如下所示:

1 JButton button = new JButton(regularIcon);
2 button.setRolloverEnabled(true);
3 button.setRolloverIcon(new RolloverIcon(regularIcon));
4

 

  下一步是创建能够将初始图标包装起来并用 图 1所示的图形效果给图标着色的 RolloverIcon 类。

  RolloverIcon

  RolloverIcon 类将实现 javax.swing.Icon 接口,这个接口允许按钮的 rolloverIcon 属性取有效值并将初始图标存储到名为 fIcon 的实例变量中:

  public class RolloverIcon implements Icon { protected Icon fIcon; {

  一种变通的解决方案可能是创建 JButton 的子类,并将翻转效果封装到这个子类中,不过,通过将逻辑放到 RolloverIcon 类中,图形效果也可以在其它情形(如复选框或菜单项)中使用。假设想得到定制的子类,那么使用创建图形效果的逻辑并将这个逻辑委托给 RolloverIcon 的实例是个很简单的做法。

  javax.swing.Icon 接口有三个方法: getIconWidth()、getIconHeight() 和 paintIcon(Component,Graphics,x,y) 。前两个方法可以委托给 RolloverIcon 正在为它创建图形效果的图标,因为翻转图像的大小将与原来图像的相同。

1 public int getIconHeight() {
2   return fIcon.getIconHeight();
3 }
4 public int getIconWidth() {
5   return fIcon.getIconWidth();
6 }
7

 

  绘制(paint)方法是将对图形上下文进行实际绘图的方法。Component 参数代表正在为之绘制图标的控件,如 javax.swing.JButton 的实例。这个方法允许我们访问诸如控件的字体、插图等细节问题,以及我们在绘制图标时可能想考虑的其它属性。x 和 y 参数是在绘图表面上正在对该图形进行着色的位置。这些位置是绘图表面的绝对位置,与从组件的 getLocation() 返回的值不同,后者是按钮相对于其父容器的位置。绘图 API 需要使用绝对值,以便将它们传递到 paintIcon 方法中,避免不得不遍历组件的所有父容器来计算这些值。

  graphics 参数是代表绘图表面的对象。虽然它的类型是 java.awt.Graphics,但它将是 java.awt.Graphics2D 的实例。Graphics2D 抽象类是 Java2D API 的一部分,它是出于向后兼容的目的作为 Java2 平台的一部分引入的,绘制方法的参数没有被重新转换为 Graphics2D 类型,尽管只要使用的 JRE 是 Java2 或更高版本就可以保证这个参数是 java.awt.Graphics2D 的实例。

  paintIcon 方法的完全说明如下所示:

 

  public void paintIcon(Component c, Graphics g, int x, int y);

  RolloverIcon 实例将包装我们希望用 图 1中所示的图形效果绘制的初始图标。我们可以使用 Graphics2D 对象的 composite 属性做到这一点。composite 属性的类型是 java.awt.Composite 接口,并且由 Graphics2D 对象完成的对图形表面的所有图元绘图都直接通过对象的 composite 进行。存在许多现成的合成类,如其中有一个是用于创建异或(XOR)效果的。XORComposite 是 sun.java2d.loops.XORComposite 类,它的构造函数以要着色成异或效果的绘图的颜色为参数。每种颜色由红、绿和蓝值组成,如果用黑色(黑色的 r、g、b 值为 0、0、0)对颜色进行异或,则该颜色将被反转。要看到这种效果,绘制方法可以编写成如下所示:

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(new sun.java2d.loops.XORComposite(Color.black));
5   fIcon.paintIcon(c,g,x,y);
6   g2D.setComposite(oldComposite);
7 }
8

  要对初始图标(保存在实例变量 fIcon 中)进行着色,我们只要遵从它的 paintIcon(Component,Graphics,int,int) 方法(这个方法已经将图形的 composite 预先设置为 XORComposite 对象)就行了。在操作图形对象的属性时,在完成之后将这些属性恢复成原来的值是一种很好的做法。在上面的方法中显示了这一点,我们在修改 composite 之前先将原来的 composite 存储起来,然后在完成修改之后将它恢复。如果您没有这样做,则 XORComposite 将会被保留在图形对象中,并且会影响到随后的所有绘图操作。

  图 2显示了 XORComposite 的效果。上面那行按钮是 RolloverIcon 被设置成 rolloverIcon 属性的原来的按钮。下面那行按钮是被永久性地设置的,用来显示被设置成 icon 属性的 RolloverIcon 的结果。XORComposite 接受图标并通过用 0 对图标的每个像素进行异或来转换它。

         图 2. XORComposite 可以用来控制如何对图标进行着色 

  异或的效果虽然不是如 图 1 所示的结果,但它确实表明了 composite 是如何负责在图标的绘图表面上进行着色的。如果我们创建自己的能让我们访问图标的精确着色的合成类,那我们就应该能够实现我们所期望的翻转效果。我们的类将叫做 RolloverComposite ,并且 paintIcon 方法可以在对初始图标进行着色之前将所期望的效果在图形对象中进行设置。

  在实现 RolloverComposite 类之前,我们需要了解关于在 Java 语言中如何表示颜色以及如何将这些颜色绘制到绘图表面上去的更多知识。

0
相关文章