OM或CENTER,以及水平方向上的LEFT、RIGHT或CENTER。构造器需要两个图标实例,并需要垂直对齐和水平对齐。我们会查看对齐是否有效,假如对齐不好,或装饰图标比被装饰图标大,你就会得到IllegalArgumentException异常。我们用GetIconWidth()和getIconHeight()来返回被装饰图标(两个图标中较大的那个)的宽度和高度。然后用paintIcon()方法先绘制被装饰的图标,再在指定的位置上绘制装饰图标。
FilterIcon类可以将一个ImageFilter用于一个指定的Icon实例。这是在构造器中实现的,另外,它还缓存了结果图像,以便在绘图时使用。我选用了ImageFilter,它是老的AWT的一部分,因为通过它,我们也可以用Java 2D最近提供的BufferedImageFiler(BuffereredImageFilter实现了ImageFilter接口)。接下来的工作就是返回所创建的图像的宽度和高度了,并在调用paintIcon()方法时,在x、y位置上画图。
我刚刚讲述的三个类可以让你在现有的Swing组件中显示合并的、被装饰的和被过滤的图标。我们可以嵌套这些Icon的实现形式,从而根据你的需要来组合或调整图标。遗憾的是,没有一个Swing组件可以提供多个状态视图,因此下面就让我们来看看如何实现这样一个组件,它可以让你处理多个图标来显示与你的应用程序相关的状态。
我们来看看所实现的JIcon中的两个重要的类,IconListModel和JIcon类本身IconListModel是个接口,它可以存储多个用于JIcon的图标。它可以以列表中当前索引的形式来治理数量不定的一列图标实例和当前选择的状态。要实现一个IconListModel接口,我们也必须将事件发送到任何注册的ChangeListener以便反映状态或Icon列表内容的变化,从而使视图(如JIcon)可以立即反映这些变化。注重,IconListModel扩展了Icon接口:public interface IconListModel
extends Icon
{
public int getIconCount();
public int getCurrentIndex();
public Icon getIcon(int index);
public void setIcons(
Icon[] icon);
public void addIcon(Icon icon);
public void removeIcon(
Icon icon);
public void setCurrentIcon(
int index);
public void addChangeListener(
ChangeListener listener);
public void removeChangeListener(
ChangeListener listener);
}
通过这个接口,我们就可以很轻易地看到需要什么步骤来实现它了,即IconList的作用(见列表1)。我们运用了两个ArrayList实例:一个用来治理ChangeListener实例的列表,另一个用来治理Icon实例的列表。我们将宽度和高度值缓存起来,当调用Icon的getIconWidth()和getIconHeight()方法时,返回这些值。宽度和高度是作为图标列表的最大值通过calculateSize()方法计算的,当列表内容发生改变时,就会调用该方法。
我们也保留当前图标和索引值来反映当前选择的状态。当paintIcon()方法在Icon接口被调用时,就会绘制所选择的图标。假如有必要,我们还提供了一个setIcons()方法来设置整个列表的内容。两个构造器中的第二个构造器在初试化时用该方法来设置列表。另一个构造器是空的,需要在一个单独的步骤中填充列表。调用addIcon()或removeIcon()方法时,也会调用calculateSize()和fireChangeEvent()方法。我们运用了一个实用的方法(capIndex())来确保当前索引值永远不会超过列表的大小。FireChangeEvent()、addChangeListener()和removeChangeListener()方法治理注册的ChangeListener的列表。
突出焦点
缺省情况下,在JIcon类中,我们用一个单独的像素EmptyBorder环绕在图标四周,这样我们就可以用一个蓝色的LineBorder来重点显示图标了。你可以调用setFocusable()方法来激活该行为。缺省情况下,我们可以处理鼠标事件(mouse event),但不接受聚焦显示。通过三个构造器我们可以创建一个空的JIcon、带有一个单独的图标的JIcon或带有一个初始Icon列表的JIcon。在每种情况中,我们都用initComponent()方法来设置可选的美学效果和监听器(listener)。
JIcon实现了四个监听器:ChangeListener、FocusListener、MouseListener和KeyListener。触发ChangeListener事件可以重画视图。我们用了一个叫做resetSize()的方法,因为模式的变化会影响由组件返回的首选的、最小的尺寸。实际的尺寸是由IconList缓存的,当图标被添加或删除时,IconList就会计算实际尺寸,因此首选的、最小的尺寸就会根据当前的getIconWidth()和getIconHeight()方法值被更新,并根据现有边界进行调整。
假如有必要,可以用FocusListener的focusGained()和focusLost()方法来改变边界。我们可以通过调用标准的isFocusable()方法来查看是否可以运用该行为。注重,Java 1.4对setFocusable()和isFocusable()方法都有介绍。假如你需要向后兼容(backward compatible),你必须修改代码来运用isFocusTraversible()方法。
KeyListener和MouseListener方法可以用来响应用户的输入。对于KeyListener来说,我们可以通过调用nextIcon()方法对空格键作出响应。MousePressed事件的作用是一样的,但先要有个焦点(focus)。在这两种情况中,我们都调用重画方法来刷新视图。我在实现的例子中已经提供了nextIcon()和prevIcon()方法,虽然我们只用了nextIcon()方法。
NextIcon()方法从模式中提取当前索引值,并以增值(increment)顺序