本节包含两个超出登录屏幕例子范围的技术。在创建您自己的 Synth 外观时,您可能发现这两项技术很有用。
绘制非 Swing 组件
可以改变每个 Swing 组件的外观这一点虽然很棒,但是还应该能够改变其他组件 —— 开发人员创建的用于填补 Swing 空缺的组件 —— 的外观。在这种情况下,
式样的分层结构
除了在创建 XML 文件时使用 KISS 式样之外,还可以构建分层次的一些式样,并将这些式样应用于组件中。清单 9 应该可以清楚地演示这一点。注意,Synth 使用最后定义的属性来显示组件。
清单 9. 分层结构的例子
2 <color value="BLACK" type="BACKGROUND"/>
3 <state>
4 <font size="14"/>
5 </state>
6 </style>
7 <bind style="base" type="region" key=".*"/>
8 <style id="sublevel" clone="base">
9 <color value="RED" type="BACKGROUND"/>
10 </style>
11 <bind style="sublevel" type="region" key="Label"/>
清单 9 中的代码使每个组件有一个黑色的背景,字体大小为 14,但 label 组件除外,label 组件拥有红色的背景。通过克隆 sublevel 中的 base 式样,清单 9 复制了整个式样。然后,您可以覆盖所需的任何特定属性。
检验 Synth 的性能、可靠性和效率
至此,您已经看到如何创建用于 Synth 的 XML 文件,以及如何通过更改字体、更改颜色和添加图像来创建定制的外观,但对于 Synth 可能还有些疑问。如果您使用 Swing 已经有一段时间,那么我可以肯定,您首先想到的是性能问题。我设计了一些性能测试,这些测试表明,Synth 不会令您的 UI 慢如蜗牛。为了调查您可能看到的问题(并讨论我在使用 Synth 时已经碰到过的一些问题),我查看了 Java Bug Parade (请参阅 参考资料)。最后,我将回答最重要的问题 —— Synth 真的可以节省您的时间吗?
装载那么多图像会不会使 Synth 变得更慢?
为了回答这个问题,我创建了两个测试,并让您更深切地体会 Synth 在性能方面与其他外观的比较。第一个测试将测试示例登录应用程序的装载时间。该测试装载 6 个 Synth 图像,并将这个装载时间与一个开发人员可能创建的一般屏幕的装载时间进行比较。第二个测试是关于装载时间的压力测试 —— 一个帧中有 100 多个组件。
两个测试都将测试 Ocean 和 Motif 外观的装载时间,以便进行比较。为了公正起见,我在三种机器上运行了这两个测试 —— 一种是安装 Windows XP 的手提电脑,一种是 SuSE Linux box,还有一种是 Red Hat Linux box。结果显示在表 1 和表 2 中。
表 1. 登录屏幕的平均装载时间
| 机器配置 | Ocean | Motif | Synth |
| Windows XP - 1.7GHz - 2GB RAM | .32 seconds | .29 seconds | .57 seconds |
| SuSE Linux 9.0 - 3.3GHz - 2GB RAM | .23 seconds | .20 seconds | .45 seconds |
| Red Hat Linux 3.0 - 1.4GHz - 512MB RAM | .37 seconds | .32 seconds | .61 seconds |
表 2. 包含 100 个组件的屏幕的平均装载时间
| 机器配置 | Ocean | Motif | Synth |
| Windows XP - 1.7GHz - 2GB RAM | .33 seconds | .32 seconds | .34 seconds |
| SuSE Linux 9.0 - 3.3GHz - 2GB RAM | .23 seconds | .23 seconds | .30 seconds |
| Red Hat Linux 3.0 - 1.4GHz - 512MB RAM | .40 seconds | .40 seconds | .43 seconds |
您可以看到,Synth 外观的装载时间只比 Ocean 和 Motif 慢一点点。但是请注意,登录屏幕与压力测试会比装载更慢一些。乍一看来,这似乎很奇怪,但如果仔细研究,便可以发现起因。压力测试没有装载复选框中所使用的图像,而登录屏幕却装载了这些图像。据此可以下结论,在 Synth 外观中使用的每个附加图像增加了装载时间。与含有两个使用两种不同图像的组件的应用程序相比,使用相同图像的 100 个组件装载起来要更快一些。减少所使用图像的数量可以提高 Synth 装载时间方面的性能。
Synth 是不是像 Swing 一样,在第一次发布时满是 bug?
根据 Sun Java 开发者网站上 Bug Parade 的评判,Synth 看上去是一个比较干净、没有 bug 的产品。然而,没有哪个软件是完美的。Synth 曾经有 125 个 bug,这与 Synth 处理 JTabbedPane 的方式不成比例。因此,如果您经历到一些问题,不要感到惊讶。然而,根据 Sun 的辩护,这些缺陷都处于“关闭(Closed)”状态。但通常的情况是,如果以前存在某些问题,那么这些问题在将来也很可能会出现。
虽然 bug 数据库为 Synth 赋予了一个相对干净的形象,我在处理登录屏幕的时候还是碰到一些问题。我第一次尝试更改 JPanel 背景颜色时遭到失败。我创建了一个特定于 JPanel 的式样,并将其绑定到所有 JPanel,但这样行不通。而当我决定使用自己的定制 painter 时,事情就解决了。
一个更大的问题是当状态改变时对组件进行重新绘制。在处理按钮及其状态时,我发现,按钮上的文本不能正确地改变颜色。当初始化时,作为默认颜色的白色没有如期显示,并且直到触发了状态变化之后才出现,然后就被重新设置为默认颜色。如果仔细研究关于 Synth 的文档,就可以发现这个小花絮:“虽然可以为每种状态提供不同的字体,但在一般情况下,当组件的状态变化时,组件不会重新生效,所以,如果您试图为不同状态使用有明显不同大小的字体时,有可能会遇到字体大小的问题”。听起来似乎它们遇上了试图让 Synth 使用老的 Swing 代码的问题。因此,如果要在状态改变时更改字体,那么要小心。
Synth 看上去的确很少有 bug。但如果随处出点小问题,那些本应该行得通的代码就会行不通,我不会对此感到惊讶。不过,变通的办法不难找到。对于在工作中碰到的每个问题,我总能找到一个变通的办法。
利用 Synth 可以创建出完全专业的外观吗?
回答是肯定的。Java 1.4 中发布的 GTK+ 和 Windows XP 外观就完全是用 Synth 创建的。(那时它不是一个已公布的 API。) 所以这方面显然没有问题。
用 Synth 创建一个完整的外观比用 Java 代码编写这样的外观要快多少?
这很容易计算。这两种方法各自都包含两个步骤:
创建外观,这通常是由图形设计人员负责的工作。
将图形界面转化成代码。
不管是用 Java 编写代码还是使用 Synth,图形界面设计这部分工作所花的时间是相同的。根据我创建定制外观的经验,我估计为一个应用程序创建一个完整的外观需要两个图形设计人员两周的时间。也就是说,图像设计工作需要 4 人一周(person-week)的人力。
通常,根据我的经验,通过类继承的方式将图形界面翻译成立即可用的外观需要三个 Java 编程人员花大约两个月的时间。也就是说,编写 Java 代码需要 6 个人一个月(person-month)的人力。加上图形界面设计工作,通过重写 UI 类,用 Swing 创建一个完全定制的外观总共需要 7 个人一个月的工作量。这些数据有助于您明白为什么 Internet 上可供下载的定制外观是那么少。
通过将图形界面转换成一个 XML 文件,Synth 可以节省大量的时间。通过 Java 编程创建外观需要 6 个人一个月的工作量,而一个开发人员将图形界面转换成 Synth XML 文件只需两个星期。用 Synth 创建完整外观所需的工作量减少到仅仅 6 个人一周的工作量 —— 通过使用 Synth 节省了超过 5 个月的时间。对于一个由两个图形设计师和两个程序员组成的团队,在短短三个星期内便可以创建出一个完整的 Synth 外观。
结束语
Synth 将皮肤的概念引入到 Swing 中。相对于传统的用 Java 代码编写定制外观的方法,Synth 最大的优势是节省时间。一个完整的 Swing 外观可以在不到一个月的时间里完成,这比用 Java 语言编程的方法要快 5 倍。对于有干劲的开发人员,在用 Java 代码编写一个外观的时间里,他可以创建 5 个 Synth 外观。
然而,Synth 并非毫无瑕疵。通过编写 Java 代码覆盖 Swing 外观,可以同时改变应用程序的外观和感觉 。而 Synth 只允许改变应用程序的外观。这是一个很大的不同之处。外观是指应用程序中使用的颜色、字体和图形。另一方面,感觉则对应于应用程序在交互期间展现出来的行为 —— 这里指单击一下鼠标右键,那里按下一个键。例如,如果您想改变一个 JList 的行为,希望通过单击鼠标左键选中条目,然后再通过单击鼠标右键来删除条目,那么用 Synth 是无法做到这些的。您需要为新的外观编写 Java 代码。Synth 实际上应该称为一种新的 Swing 外观,而不是一种普通外观。通过 Synth 可以快速改变 UI 的外观,但 UI 的感觉永远都是默认的 Swing 感觉。
当然,如果您想通过为应用程序提供新的外观来使之整洁漂亮,或者渴望看到比令人讨厌的 Metal 外观(谢天谢地,在 Java 5.0 中它已成为历史)更好的 Swing 应用程序外观,那么 Synth 是很好的一个选择。它不存在性能问题,并且看上去 bug 也很少。Sun 已经表示,通过发布 GTK+ 外观,用 Synth 可以创建完整的外观。
令人吃惊的是,Synth 文档和实例现在还很少。阅读本文之后,对于 Synth 的工作原理您应该有一个更深的理解,并且能够使用一个组件一个样式标签(one-style-tag-per-one-component)的设计来生成一个完整的 Synth XML 文档。Synth 的继承和分层模型为创建 style 标签提供了更强大的方法,但没有它们仍然可以创建完整的外观。理想情况是:随着对 Synth 认识的加深,Swing UI 社区将出现皮肤数量的大爆炸。有了数百个可供选择的外观,通常那些加在 Swing 应用程序身上的“长相恐怖”、“丑陋”之类的责骂之词也将永远消失。