第一节 | 第二节 | 第三节 | 第四节 | 第五节 | 第六节 | 第七节 | 第八节 | 第九节 | 第十节 | 第十一节 |
第八节 Swing中的Icon和Border
|
||||||||||
对所有的Swing组件,例如按钮、列表单等,都还可以绘制边框。在Swing中提供了各种边框类型,例如bevel、etched、line、titled等。Swing组件的边框是通过JComponent类来绘制的,该类是所有Swing组件的基类,实现了所有Swing组件公共的功能。在JComponent中有一个paintBorder()方法,该方法为组件绘制边框。Swing的开发人员可以象下面的例子中所示那样来绘制边框: // 一段实现paintBorder()方法代码 protected void paintBorder(Graphics g) { switch(getBorderType()) { case LINE_BORDER: paintLineBorder(g); break; case ETCHED_BORDER: paintEtchedBorder(g); break; case TITLED_BORDER: paintTitledBorder(g); break; ... } } 请注意上面的代码只是一种假设,事实上Swing的开发人员并没有这样实现paintBorder()方法。在上面的代码中,在JComponent中绘制边框的代码被直接写入了paintBorder()方法中,这意味着JComponent和绘制边框的功能被紧密地结合在了一起。很自然地大家会联想到如果需要实现一种新的边框类型,开发人员必须修改至少三处代码:首先增加一个常量,该常量代表新添加的边框的类型值;其次需要在Switch语句中增加一个case语句;最后开发人员需要实现paintXXXBorder()方法,其中XXX代表新边框的名称。 很显然要扩展上面paintBorder()方法的功能是一件很困难的事情,不仅仅是因为开发人员需要增加一种新的边框类型,更麻烦的是开发人员很难修改JComponent类。JComponent类已经被编译到了Swing的开发工具中,如果开发人员想修改它的话,必须获得Swing的源代码,修改后重新编译Swing。同时在用户的计算机上与需要使用新编译的Swing API。另外所有的Swing组件都可以使用开发人员新添加的边框类型。有可能开发人员只希望新的边框被某些组件使用,但是现在开发人员无法对使用该边框的组件进行限制。 开发人员有更好的实现方法吗?答案就是策略模式。通过策略模式,可以将JComponent和实现绘制边框的代码分离开来,这样开发人员在增加或修改绘制边框的代码使就不需要修改JComponent的代码。通过应用策略模式,开发人员将变化的概念(在这个例子中是绘制边框)封装起来,然后通过一个Border接口,使程序能够重用绘制边框的功能。下面让我们来看JComponent是如何利用策略模式来实现绘制边框的功能的: // Swing中paintBorder()方法的源代码 protected void paintBorder(Graphics g) { Border border = getBorder(); if (border != null) { border.paintBorder(this, g, 0, 0, getWidth(), getHeight()); } } 上面的paintBorder()方法通过一个border对象绘制了组件的边框。这样border对象替代了前一个例子中的JComponent封装了边框绘制的功能。我们还应该注意到JComponent将一个对自己的引用传递给了Border.paintBorder()方法,这是因为Border的实例必须知道它对应的组件的信息,这种方式通常被称为委托。通过这种方式,一个对象可以将功能委托给另一个对象来实现。 在JComponent类中引用了一个Border对象,通过JComponent.getBorder()方法可以获得该Border对象。下面的代码演示了如何设定和获得Border对象: ... private Border border; ... public void setBorder(Border border) { Border oldBorder = this.border; this.border = border; firePropertyChange("border", oldBorder, border); if (border != oldBorder) { if (border == null || oldBorder == null || !(border.getBorderInsets(this). equals(oldBorder.getBorderInsets(this)))) { revalidate(); } repaint(); } } ... public Border getBorder() { return border; } |
||||||||||