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);
}
|