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

Swing框架之UI Delegate之二

 

作者:WilliamChen

 

 

LookAndFeel子类
        LookAndFeel类声明了如下抽象方法,继承它的子类必须实现这些方法:
                                                                                     
   public String getName();
   public String getID();
   public String getDescription();
   public boolean isNativeLookAndFeel();
   public boolean isSupportedLookAndFeel();

        getName()、getID()以及getDescription()方法返回描述LAF的普通属性。如果LAF相对当前平台是本地外观,那么isNativeLookAndFeel()方法返回true。比如,运行在Solaris操作系统上时MotifLookAndFeel返回true,其他平台则返回false。isSupportedLookAndFeel()方法返回该LAF是否允许运行于在当前平台上,比如WindowsLookAndFeel在所有Windows操作系统上都返回true。LookAndFeel类还提供了初始化和卸载的方法:

  public void initialize()
   public void uninitialize()

        当使用UIManager.setLookAndFeel()方法将LookAndFeel设置成缺省的LAF时,UIManager调用该LAF类的initialize()方法,当LookAndFeel被其它LookAndFeel所替换时,UIManager调用它的unintialize方法。

Defaults Table

        此外LookAndFeel类还提供返回LAF的Defaults Table的方法:

   public UIDefaults getDefaults()

        Defaults Table是一个UIDefaults对象,UIDefaults继承java.util.Hashtable,还添加了访问LAF某些类型信息的专门方法。该表须包括UIClassID对classname的映射信息,还要包括许多展现相关属性的缺省值,比如颜色、字体、边框和图标等。下面例子假设有一个LAF实现,其LAF包名为mine,那么getDefaults()方法的代码应该如下:

public UIDefaults getDefaults() {
   UIDefaults table = new UIDefaults();
   Object[] uiDefaults = {
     "ButtonUI",   "mine.MyButtonUI",
     "CheckBoxUI", "mine.MyCheckBoxUI",
     "MenuBarUI",  "mine.MyMenuBarUI",  
         ...
    
     "Button.background",
         new ColorUIResource(Color.gray),
     "Button.foreground",
         new ColorUIResource(Color.black),
     "Button.font",
         new FontUIResource("Dialog", Font.PLAIN, 12),
     "CheckBox.background",
         new ColorUIResource(Color.lightGray),
     "CheckBox.font",
         new FontUIResource("Dialog", Font.BOLD, 12),
         ...
   }
   table.putDefaults(uiDefaults);
   return table;
}

        当通过UIManager.setLookAndFeel()设置缺省LAF时,UIManager调用该LookAndFeel实例的getDefaults()方法,并存储返回的hash表。之后对于UIManager查找方法的调用将作用到该表上,比如将“mine”设置成缺省LAF后,下面代码返回ButtonUI对应的实现类mine.MyButtonUI。

UIManager.get("ButtonUI") => "mine.MyButtonUI"

        UI类使用相同方法访问缺省信息,如ButtonUI类使用如下代码初始化JButton的background属性:

button.setBackground(
    UIManager.getColor("Button.background");

区分UI和应用程序设置的属性

        Swing允许应用程序单独对组件设置属性值(颜色、字体等),保证这些值不和LAF设置的缺省值相冲突很重要。在组件UI delegate第一次初始化时(在组件的构造函数中)这还不是个问题,因为所有属性都可以卸载,且可通过LAF来设置。问题出现在当应用程序在组件构造完毕后,单独设置这些属性,然后设置新的LAF时(也就是动态切换LAF)。这意味着LAF须能区分应用程序和LAF设置的值。

        解决此问题的方法是通过javax.swing.plaf.UIResource接口标识所有通过LAF设置的值。javax.swing.plaf包提供了一些“标识”类来表达这些值,比如ColorUIResource、FontUIResource以及BorderUIResource,前面所述代码演示了如何使用这些类来标识MyButtonUI类的缺省属性值。

UI delegate对象

        所有UI Delegate类的基类是javax.swing.plaf.ComponentUI,此类包含了可插拔LAF工作原理的基本“机制”,其方法包括UI安装、卸载以及代理组件几何布局和重画等。许多UI Delegate子类还提供同特定组件进行交互的方法。本文只讲述ComponentUI实现的通用机制。

UI安装和卸载

        ComponentUI类定义了如下方法来安装和卸载UI Delegate对象:

  public void installUI(JComponent c)
  public void uninstallUI(JComponent c)

        看一下JComponent.setUI()的代码实现,就能清晰地看出UI delegate安装与卸载是如何工作的。注意ComponentUI的子类总是激活JComponent的setUI方法实现各自的setUI。

protected void setUI(ComponentUI newUI) {
   if (ui != null) {
      ui.uninstallUI(this);
   }
   ComponentUI oldUI = ui;
   ui = newUI;
   if (ui != null) {
      ui.installUI(this);
   }
   invalidate();
   firePropertyChange("UI", oldUI, newUI);
}

    
        下图是一幅描述安装和卸载UI delegate对象过程的示意图:

        UI delegate的installUI()方法负责以下过程:

  • 设置组件的缺省字体、颜色、边框、透明属性。
  • 为组件安装适当的布局管理器。
  • 向组件添加适当的子组件。
  • 为组件注册必须的事件处理器。
  • 为组件注册特定LAF的键盘动作(快捷键等)。
  • 注册repaint时需要通知的模型listener。
  • 初始化某些适当的实例数据。

        比如,ButtonUI扩展类的installUI()可用下面代码实现:

protected MyMouseListener mouseListener;
protected MyChangeListener changeListener;  
public void installUI(JComponent c) {   
   AbstractButton b = (AbstractButton)c;
   
   // Install default colors & opacity
   Color bg = c.getBackground();
   if (bg == null || bg instanceof UIResource) {
      c.setBackground(
          UIManager.getColor("Button.background"));
   }
   Color fg = c.getForeground();
   if (fg == null || fg instanceof UIResource) {
      c.setForeground(
          UIManager.getColor("Button.foreground"));
   }
   c.setOpaque(false);
 
  // Install listeners  
   mouseListener = new MyMouseListener();
   c.addMouseListener(mouseListener);   
   c.addMouseMotionListener(mouseListener);
   changeListener = new MyChangeListener();
   b.addChangeListener(changeListener);
}


来源



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


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