您的位置: 文章阅读 ┆ 回首页
 
站内资源搜索:
┆ 将本文寄给朋友  

Swing框架之UI Delegate之三

 

作者:WilliamChen

 

 

初始化组件属性约定俗成的做法

        安装LAF时,Swing初始化组件属性的约定俗成的做法包括以下两种:

  1. 从Defaults Table获取所有用来设置颜色、字体、边框等属性的值。
  2. 颜色、字体和边框属性应该只有在应用程序没有设置它们时设置。

        对于做法1,UIManager定义了几个静态方法来获取指定类型的属性值,如getColor()和getFont()等。对于做法2,Swing通过设置属性前先检查是否为空,或者是否是UIResource实例来设置。
                                                                                     
        ComponentUI的uninstall()方法必须仔细清除所有installUI()方法的操作,让组件Component在安装另外一个UI delegate对象前处于干净的原始状态。uninstall()方法负责:

  • 删除installUI()设置的边框。
  • 删除installUI()设置的布局管理器。
  • 删除installUI()添加的组件。
  • 删除installUI()添加的事件/模型处理器。
  • 删除installUI()安装的特定于LAF的键盘动作。
  • 将任何实例化的数据设置为空(允许GC进行垃圾收集)。

        比如,为了取消前面例子中的操作,uninstall()方法代码应该如下:

public void uninstallUI(JComponent c) {
    AbstractButton b = (AbstractButton)c;
    // Uninstall listeners
    c.removeMouseListener(mouseListener);
    c.removeMouseMotionListener(mouseListener);
    mouseListener = null;
    b.removeChangeListener(changeListener);
    changeListener = null;
}

定义几何布局

        在AWT/Swing中,容器的LayoutManager会根据不同算法来布局容器的组件,即所谓容器层次结构的“有效化(validation)”。典型的LayoutManager会查询其内部组件的preferredSize属性(根据具体算法有时还会查询minimumSize和/或maximumSize),目的是精确确定组件位置、设置组件大小。LAF通常需要指定某些组件的几何属性,ComponentUI为此提供了以下方法:

public Dimension getPreferredSize(JComponent c)
public Dimension getMinimumSize(JComponent c)
public Dimension getMaximumSize(JComponent c)
public boolean contains(JComponent c, int x, int y)

        如果应用程序对这些几何属性没有明确设置,那么JComponent中的对应方法(LayoutManager在validation界面时调用这些方法)会简单将方法代理给相应UI对象,下面是JComponent.getPreferredSize()的方法实现:

public Dimension getPreferredSize() {
    if (preferredSize != null) {
        return preferredSize;
    }
    Dimension size = null;
    if (ui != null) {
        size = ui.getPreferredSize(this);
    }
    return (size != null) ? size :
    super.getPreferredSize();
}

        尽管所有组件的边界是一个Rectangle对象,但可以通过覆盖java.awt.Component继承的contains()方法来模拟非矩形组件(contains()方法用来确定鼠标事件的点击位置)。不像其他Swing的几何属性,UI delegate定义自己的contains()方法,Jcomponent的contains()方法代理给它完成:

public boolean contains(JComponent c, int x, int y) {
    return (ui != null) ? ui.contains(this, x, y) : super.contains(x, y);
}

        因此UI delegate对象可以通过特定的contains()实现提供非矩形的“感觉”(比如希望用MyButtonUI类实现一个圆角按钮)。

重画

        最后,UI delegate对象须实现当前LAF下的组件重画,为此ComponentUI定义有如下方法:

public void paint(Graphics g, JComponent c)
public void update(Graphics g, JComponent c)

        JComponent.paintComponent()方法负责组件重画过程的代理工作:

protected void paintComponent(Graphics g) {
    if (ui != null) {
        Graphics scratchGraphics = SwingGraphics.createSwingGraphics(g.create());
        try {
            ui.update(scratchGraphics, this);
        }
        finally {
            scratchGraphics.dispose();
        }
    }
}

        同AWT中使用的方法类似,UI delegate对象的update()方法清除背景(如果不透明),接着激活自己的paint()方法,最后由paint()方法渲染出组件的内容。我们在前面的文章中已经提到过这段代码:

public void update(Graphics g, JComponent c) {
    if (c.isOpaque()) {
    g.setColor(c.getBackground());
    g.fillRect(0, 0, c.getWidth(),c.getHeight());
    }
    paint(g, c);
}

无状态代理及有状态代理

        所有ComponentUI的方法的参数都有一个Jcomponent对象。这种约定俗成的做法可用来实现无状态的UI delegate对象。代理对象可通过查询组件来获得信息。无状态UI delegate的实现,允许单个UI delegate实例被所有此组件实例共享,极大减少了实例化的代理对象。

        ComponengUI定义了一个静态方法,返回代理实例:

public static ComponentUI createUI(JComponent c)

        此方法的具体实现决定了代理是否是无状态的,组件通过激活UIManager.getUI()方法来创建UI delegate,而getUI()激活该UI delegate的静态方法createUI()来产生实例。这两种类型的代理对象在Swing的LAF实现中都有,比如Swing的BasicButtonUI实现了无状态的代理:

// Shared UI object
protected static ButtonUI buttonUI;
public static ComponentUI createUI(JComponent c)
    if(buttonUI == null) {
        buttonUI = new BasicButtonUI();
    }
    return buttonUI;
}

        而Swing的BasicTabbedPaneUI实现了有状态的代理:

public static ComponentUI createUI(JComponent c){
    return new BasicTabbedPaneUI();
}

LAF总结

        Swing可插拔外观的功能很强大,但也是很复杂。其设计目的是,供少数需要实现新外观的开发者使用。应用程序开发者只需要理解这种机制的能力,以便决定支持外观的策略,是使用单一外观还是支持用户配置的多外观。Swing的UIManager为应用程序在这一层的管理提供了编程接口。你如果需要定义一套自己的外观,在编写程序前理解这些基础知识很重要的。

        到此为止,Swing体系结构中的UI Delegate部分已经讲完了。明天继续讨论Renderer和Editor机制。



来源



以上文章版权由原作者所有。未经同意,不得将其任何一部分复制、转载、发布等未授权操作。


Java学习室 — 陈伟波个人主页
E-mail: zz3zcwb@sina.com
COPY RIGHT 2005