【IT168 技术文章】文将深入透视 Synth 外观,它是 Java 5.0 中为 Swing 引入的最新内容。通过为 Java UI 编程引入“皮肤”的概念,Synth 使开发人员可以为应用程序创建和部署定制的外观。软件工程师 Michael Abernethy 将带您从头开始逐步构建一个具有 synth 外观的应用程序,让您充分了解 Synth 的概念。阅读本文之后,您应该可以在短时间内创建具有专业外观的 UI。
就在 Sun 一如既往地试图“再次引入 Java Desktop”之际,Java UI 开发人员的抱怨之词亦已表面化:要创建完全定制的外观实在太难。这样做不仅要花费太多的时间,并且 Swing UI 代码的编写和文档的编制也极为不堪,常常是乱杂一气,缺乏规划。为了创建完整的外观,开发人员需要继承 Metal 外观的 39 个类,或者继承 Basic 外观的 60 个类。谁想通过重写整个包来改变应用程序呈现外观的方式呢?用 Swing 创建定制外观有多难,通过下面的事实同样可窥见一斑:在很多开发人员为开源项目添砖加瓦的时代,Internet 上可用的自定义 Swing 外观几乎是凤毛麟角 —— 总共大约是 20 个,其中少数在 SourceForge.net 上。
美丽只是肤浅的东西
进入 Synth,Sun 希望它能使应用程序外观的个性化过程变得容易。Synth 的目标很简单 —— 让开发人员不必编写任何代码就可以创建新的外观。这似乎是个不错的解决方案。程序员一般没有突出的艺术才华,而图形设计人员通常也不是 Java 编程专家。Synth 把对外观的所有描述从代码中分离出来,而将其放入外部的 XML 文件和图像文件中,为上述问题提供了大快人心的解决之道。这种完全在外部文件中描述的外观被称作皮肤(skin)。
Sun 的皮肤概念并不是什么创新。例如,Winamp 有数百种皮肤,Firefox 也有几十种皮肤,这些皮肤很容易创建,只需更改一个 XML 文件即可。想像一下,仅仅修改一个 XML 文件,就能快速、容易地为 Java 应用程序创建一个外观。再想想这样一来的结果 —— 几百个互不相同的 Swing 外观。Java UI 开发人员当然有理由欢呼了。
本文将深入分析 Synth 外观,向您展示创建一个完整的外观或皮肤所需知道的一切。您会看到一个带有示例皮肤的应用程序,这个应用程序使用了 Synth 所有重要的概念。然后,我会逐步剖析这个皮肤,在构建 XML 文件的过程中,一一教会您 Synth 的各个概念。
本文最后一节将尽力回答开发人员关于 Synth 性能、bug 和缺陷以及 Synth 在省时方面的表现等种种问题。阅读本文之后,您应该会愿意拥护 Synth 作为外观解决方案,并准备马上使用它来创建自己的 Swing 外观。
Synth 基础
Synth 是一个白板(tabula rasa)外观 —— 一块完全空白的画布,表现为一个完全空白的面板(panel),只有在 XML 文件中定义了组件时,它才会显示东西。一旦定义了组件,在应用程序上设置 Synth 外观就再容易不过了,如清单 1 所示:
清单 1. 设置 Synth 外观
2 synth.load(SynthFrame.class.getResourceAsStream("demo.xml"), SynthFrame.class);
3 UIManager.setLookAndFeel(synth);
但是,对于 Synth,最重要的是要理解它是 XML 代码,而不是 Java 代码。虽然 Synth XML 格式一开始看上去比较吓人,但实际上很简单。如果使用 KISS (Keep It Simple Stupid)这道符咒,您可以快速地创建一个 XML 文件,并得到一个新的、可以运行的外观。
考虑到 KISS 指令,我将首先介绍 Synth XML 文件的主要构件 —— <style>标签。<style>标签包含描述一个组件的式样的所有信息,例如颜色、字体、图像文件、状态,以及一些特定于组件的属性。虽然一个<style>标签可以描述多个组件,但构建 Synth 文件的最简便方法是为每个 Swing 组件创建一个式样。
创建好式样之后,便可以将式样链接到一个组件。<bind>标签通知 Synth 引擎将一个已定义的式样链接到一个组件,如清单 2 所示。这样的组合便完全创建了组件的新外观。
清单 2. 将一种式样链接到一个组件
2 // describe colors, fonts, and states
3 </style>
4 <bind style="textfield" type="region" key="Textfield"/>
5 <style id="button">
6 // describe colors, fonts, and states
7 </style>
8 <bind style="button" type="region" key="Button"/>
关于 <bind>
标签,要注意的一点是:<bind>
标签中的 key
属性映射到javax.swing.plaf.synth.Region 类中的常量。Synth 引擎使用这些常量将式样与一个实际的 Swing 组件链接。简单的组件,例如 JButton
和 JTextField
,使用一个常量。有些更复杂的组件,例如 JScrollBar
和 JTabbedPane
,则有多个常量,用于不同的部分。
我建议您在更熟悉 Synth 格式并且能够设置 XML 中的继承模型之前,使用每个组件一种式样(one-style-per-component)的设置。这种结构虽然没有利用所有 XML 的分层结构功能,但它是最容易设置、编写代码和调试的。
在处理 Synth XML 文件时,还有一点很重要,并不是任何形式都是合法的。如果有输入错误,或者在 XML 中使用了不正确的属性,这些错误只有当外观装载期间抛出一个运行时异常时才能发现。解决方法:在将 XML 文件发布给客户之前,对其进行测试。