程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 高級Synth:有了最新的Swing外觀,定制UI不在話下

高級Synth:有了最新的Swing外觀,定制UI不在話下

編輯:關於JAVA

簡介:本文將深入透視 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 外觀

SynthLookAndFeel synth = new SynthLookAndFeel();
  synth.load (SynthFrame.class.getResourceAsStream("demo.xml"), SynthFrame.class);
  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. 將一種式樣鏈接到一個組件

<style id="textfield">
  // describe colors, fonts, and states
</style>
<bind style="textfield" type="region" key="Textfield"/>
<style id="button">
  // describe colors, fonts, and states
</style>
<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 文件發布給客戶之 前 ,對其進行測試。

Demo 應用程序

我將帶您構建一個簡單的登錄屏幕,用它作為例子應用程序,向您展示 Synth XML 文件的工作原理。該屏幕提供了足夠多的組件,通過這些組件,可以看到 XML 文件的所有重要部分,如果使這些部分結合起來便可以創建一個完整的外觀 。

通過比較圖 1 和圖 2,具有 Ocean 外觀的登錄屏幕看上去與您預期的一樣 —— 簡單,直接,也令人厭煩。具有 Synth 外觀的登錄屏幕則完全不同。

圖 1. 具有 Ocean 外觀的 Demo 應用程序

圖 2. 具有 Synth 外觀的 Demo 應用程序

更改顏色和字體

為 demo 應用程序創建外觀的第一步是設置默認顏色和字體。您將把 white Aharoni 字體作為每個組件的默認字體,如果沒有特殊設置組件的話,就使用這 種字體。

您可以將更改字體的 XML 放在 <style> 標簽內的任何地方。還可以 將 顏色嵌入到一個 <state> 標簽中。在本文的後面部分,我將更詳細地討 論 <state> 標簽,但現在只需知道,一個簡單的、不帶屬性的 <state> </state> 標簽可以包含任何狀態,這個標簽正是您在這 裡 所需要的。

color 標簽本身需要兩個屬性:

value 可以是 java.awt.Color 常量的任何 String 表示(例如 RED、BLUE ) ,或者,它可以是一種顏色的十六進制表示,前面加上 "#" (例如 #669966) 。

type 描述文件應該設置哪個區域的顏色。選擇有 BACKGROUND、FOREGROUND 、 TEXT_FOREGROUND、TEXT_BACKGROUND 和 FOCUS。

font 標簽有兩個必需的屬性和一個可選屬性。這三個屬性直接映射到 java.awt.Font 類中的三個參數:

name :字體的名稱(例如,Verdana、Arial)。

size :字體大小,以像素為單位。

style :如果不使用這個可選標簽,那麼將得到常規外觀的字體。其他選項 包 括 BOLD 和 ITALIC。您還可以通過在這兩個屬性之間加一個空格來指定粗體加 斜 體的字體:BOLD ITALIC(這種組合屬性的技術對於 Synth XML 文件中的所有屬 性都適用)。

最後,通過使用 .* wildcard,將這個式樣綁定到應用程序中的每個組件, 而 不是將其綁定到每個 JLabel 和每個JButton。這個通配符告訴 Synth 外觀為每 個組件指定一個默認的 white Aharoni 字體。清單 3 展示了用於設置組件字體 和顏色的完整 XML 代碼:

清單 3. 更改多個組件的字體和顏色

<style id="default">
  <font name="Aharoni" size="14"/>
  <state>
   <color value="#FFFFFF" type="FOREGROUND"/>
  </state>
</style>
<bind style="default" type="region" key=".*"/>

使用圖像

圖 2 中的 textfield 邊框不是常規外觀的單像素矩形邊框。可以使用一個 圖 像來創建這些邊框。這不是我們所熟悉的概念 —— 圖像用在 button 和 label 中已經有些時候了 —— 但您可以想像在哪些地方會出問題。如何知道光標移動 到什麼地方,如何顯示文本,如何創建不同大小的文本域?這些問題可以通過圖 像拉伸(image stretching)的概念來解決。一個圖像文件必須描述應用程序中 文本域各個邊的長度,因此需要有一種方式來告訴 XML 文件如何適當地拉伸圖 像 ,以及如何處理常規的 textfield 活動(carat 和文本控制)。

幸運的是,從早期帶皮膚的應用程序起,就有一個方法可用於處理這種類型 的 拉伸。圖像必須分成 9 個區域 —— 頂部、右上、右部、右下、底部、左下、 左 部、左上和中間 —— 這些區域是通過 XML 文件中的一個屬性來指定的。然後 呈 現程序可以通過一定的方式拉伸圖像,以適合指定的空間。圖 3 展示了文本域 圖 像是如何拉伸的。

圖 3. 在 Synth 中圖像如何拉伸

Synth 外觀

圖 3 中綠色填充區只會垂直拉伸。也就是說,當文本域比圖像高的時候,這 些區域就會變高。當文本域比圖像長的時候,那些紅色填充區只會水平拉伸。而 黃色填充區則是大小固定的。不管文本域的大小如何,這些區域都會如它們在圖 像文件中那樣顯示。因為這些區域不會拉伸,因此它們應該包含所有畫布、特殊 底色、陰影和任何一旦拉伸就會看起來很古怪的東西。最後,中間區域是可選的 。您可以選擇畫出或者忽略該區域。在我們的例子中,文本域的中間被忽略。此 後,呈現程序使用這個區域來處理文本控制和 carat。也就是說,使用一個圖像 文件完全畫出文本域。

imagePainter標簽提供了在外觀中使用圖像所需的所有信息。它只需要幾個 屬性:

path :所使用的圖像的路徑。

sourceInsets :按像素計算的 insets,表示圖 3 中綠色區域的寬度和粉紅 色區域的高度。它們依次映射到頂部、左部、底部和右部。

method :這也許是最令人費解的屬性。它直接映射到 javax.swing.plaf.synth.SynthPainter類中的一個函數。這個類包含大約 100 個函數,所有這些函數都以 paint開始。每個函數映射到在一個 Swing 組件中 某個特定的繪畫任務。您只需找到一個合適的函數,然後去掉 paint字符串,並 使隨後的首個字母為小寫形式,便可以設置該屬性。例如, paintTextFieldBorder是 textFieldBorder的屬性。呈現程序(renderer)負責 剩下的工作。

paintCenter :該屬性允許您保留或者捨棄圖像的中間區域(例如在一個按 鈕中)。在這個例子中,textfield捨棄了中間區域,以便顯示文本。

使用圖像畫邊框的最後一步是加大默認的 insets,以便處理用來畫這些 insets 的圖像。如果沒有更改 insets,那麼就看不見任何圖像。您需要添加一 個 <insets>標簽來增加 insets,以便在其中畫出圖像。在大多數情況下 ,insets 的值應該與在圖像中使用的 insets 的值相同。

清單 4 展示了用於裝載圖像的 XML 代碼。注意 sourceInsets如何確保圖像 只有適當的部分被拉伸。

清單 4. 裝載圖像

<style id="textfield">
<opaque value="true"/>
<state>
<font name="Aharoni" size="14"/>
<color value="#D2DFF2" type="BACKGROUND"/>
<color value="#000000" type="TEXT_FOREGROUND"/>
</state>
<imagePainter method="textFieldBorder" path="images/textfield.png"
sourceInsets="4 6 4 6" paintCenter="false"/>
<insets top="4" left="6" bottom="4" right="6"/>
</style>
<bind style="textfield" type="region" key="TextField"/>

處理不同的狀態

從前面的例子可以看到,<state>標簽是定義一個組件的焦點所在。在 清單 3和清單 4中,color 和 font 標簽都處在 <state>標簽內。現在我 將解釋 <state>標簽的作用。

默認狀態是在 <state>標簽中沒有指定屬性,這對於定義文本域和 label 中的顏色和字體已經足夠了,因為這兩種組件的狀態不會改變。但是在那 些狀態會改變的組件中(例如按鈕),可以為每種狀態定義完全不同的外觀。每 種狀態可以有它自己的顏色、字體和圖像。您可以比較登錄屏幕中 Cancel按鈕 在默認狀態(圖 4)和 mouse-over 狀態(圖 5)下的不同。

圖 4. DEFAULT 狀態下的 Cancel 按鈕

Default 狀態

圖 5. MOUSE_OVER 狀態 下的 Cancel 按鈕

Mouse over 狀態

<state>標簽只需要一個 value屬性,該屬性定義了實際的組件狀態。 如果沒有指定 value,如清單 3 和 4 所示,那麼每種狀態都使用默認值。如果 指定 value屬性,那麼可以選擇 ENABLED、MOUSE_OVER、PRESSED、DISABLED、 FOCUSED、SELECTED和 DEFAULT。這些選擇包含 Swing 中任何組件所有可能的狀 態。您還可以在不同選擇間添加 and來組合各種狀態。例如,如果您想在鼠標位 於按鈕之上以及按鈕被按下的時候改變按鈕上的字體,那麼可以使用狀態值 MOUSE_OVER and PRESSED。

清單 5 展示了用於處理 demo 應用程序狀態的 XML。注意每種狀態是如何定 義不同的圖像和文本顏色的。

清單 5. 處理狀態

<style id="button">
<state>
<imagePainter method="buttonBackground" path="images/button.png"
sourceInsets="9 10 9 12" paintCenter="true" stretch="true"/>
<insets top="9" left="10" bottom="9" right="12"/>
<font name="Aharoni" size="16"/>
<color type="TEXT_FOREGROUND" value="#FFFFFF"/>
</state>
<state value="MOUSE_OVER">
<imagePainter method="buttonBackground" path="images/button_on.png"
sourceInsets="9 10 9 12" paintCenter="true" stretch="true"/>
<insets top="9" left="10" bottom="9" right="12"/>
<color type="TEXT_FOREGROUND" value="#FFFFFF"/>
</state>
<state value="PRESSED">
<imagePainter method="buttonBackground" path="images/button_press.png"
sourceInsets="10 12 8 9" paintCenter="true" stretch="true"/>
<insets top="10" left="12" bottom="8" right="9"/>
<color type="TEXT_FOREGROUND" value="#FFFFFF"/>
</state>
<property key="Button.margin" type="insets" value="0 0 0 0"/>
</style>
<bind style="button" type="region" key="Button"/>

處理 標簽的一個重要方面是知道哪些組件有哪些狀態。顯然,在這 個例子中,按鈕可以擁有默認狀態、鼠標懸停(mouse-over)狀態和被按下 (pressed) 狀態。對於這個例子,還可以定義一個聚焦(focused)和禁用 (disabled)狀態。但是對於一個面板,選中(selected)狀態根本不適用,當 鼠標處於面板之上時如果改變面板的狀態,那麼只能招來抱怨。

處理特定於組件的屬性

定義對每種組件都通用的 XML 屬性時,總是忽略了一些特定於組件的屬性。 例如 list 的行高、單選鈕的圖標和菜單的箭頭圖標,這些都是特定於組件的屬 性。可以定義的特定於組件的屬性有 100 多種,但是為每個這樣的屬性定義一 個 XML 屬性就有些過分了。因此,Synth XML 文件允許設置特定於組件的屬性 。<property>標簽就像一個 Hashtable,它定義一個鍵 / 值對來設置屬 性。

登錄屏幕示例的復選框演示了如何為特定於組件的屬性編寫代碼。通過定義 imageIcon,可以設置默認狀態和選中狀態下的 CheckBox.icon。這就像是翻遍 100 個屬性找到您想要的屬性那樣簡單。

清單 6 展示了為登錄屏幕中特定於組件的屬性編寫代碼的 XML。注意要首先 定義 imageIcon。然後,通過使用圖像圖標的 ID,可以為復選框的每種狀態設 置一個圖標。

清單 6. 定義特定於組件的屬性

<style id="checkbox">
<imageIcon id="check_off" path="images/checkbox_off.png"/>
<imageIcon id="check_on" path="images/checkbox_on.png"/>
<property key="CheckBox.icon" value="check_off"/>
<state value="SELECTED">
<property key="CheckBox.icon" value="check_on"/>
</state>
</style>
<bind style="checkbox" type="region" key="Checkbox"/>

使用定制 painter

定義 圖 2中登錄屏幕例子的最後工作是用曲線繪制漸變背景。用 XML 來實 現這種背景似乎有些別扭,坦白地說,真是這樣。但這樣我便有機會展示 Synth ,不限制您在 UI 設計中只使用圖像和簡單的顏色。您可以使用它來畫任何東西 。

Synth 允許重寫其 paint 方法(即在 javax.swing.plaf.synth.SynthPainter類中的方法),該方法繼承自 SynthPainter,它將覆蓋那些您想要定制繪畫方式的特定函數。在這個例子中, 需要定義 paintPanelBackground方法,因為這種設計不能以 Synth XML 格式描 述。

為了使用定制的 painter,或者在 XML 中以任何方式創建一個類,可以使用 <object>標簽。<object>標簽允許創建和保持用於彌補 Synth 呈 現程序的任何 Java 類。<object>標簽帶有兩個元素:

class :將創建的類的全名。

id :用於在 XML 文檔中引用這個類實例的 ID 名。

通過使用對象,不僅可以創建 BackgroundPainter類的實例 —— 這 個類將用於繪制背景,而且還可以創建 ColorUIResource類的實例,在這個類中 可以定義背景顏色。想一想:在 BackgroundPainter類中定義背景中使用的顏色 ,這與 Synth 的目標是矛盾的,Synth 的目標是在一個外部 XML 文件中定義一 切,而不是在一個 Java 文件中進行硬編碼。

使用定制 painter 的最後一步是告訴 Synth 呈現引擎,是您自己而不是 SynthPainter類來提供函數。在這個例子中,首先在 BackgroundPainter類中定 義 paintPanelBackground函數,並讓 SynthPainter類定義剩下的繪畫函數。 <painter> 標簽讓您可以覆蓋 SynthPainter 函數。它帶有兩個元素:

method :定制 painter 應該覆蓋的方法。從 使用圖像一節中您已經得知, 您可以在 javax.swing.plaf.synth.SynthPainter 類中找到這些函數,但是應 該刪除每個函數開始部分的 paint字符串(例如,SynthPainter中的 paintPanelBackground在 XML 文件中應該是 panelBackground)。

 

id:對將覆蓋此方法的類的引用。

為了在定制 painter 中使用顏色,必 須將顏色保存在 javax.swing.UIDefaults類中。在清單 7 和清單 8 中可以看 到,將顏色保存在 UIDefaults中十分簡單,對於那些接觸過 UI 創建的人來說 應該,應該比較熟悉這些內容。在 XML 文件中定義的鍵將成為 UIManager中的 引用,在 BackgroundPainter的 Java 代碼中,可以使用 UIManager來獲得顏色 。

清單 7 展示了在例子應用程序中使用定制 painter 的 XML 代碼。注意必須 首先定義顏色。

清單 7. 使用定制 painter

<style id="panel">
<object id="background" class="demo.synth.BackgroundPainter"/>
<object class="javax.swing.plaf.ColorUIResource" id="startColor">
<int>30</int>
<int>123</int>
<int>235</int>
</object>
<defaultsProperty key="Panel.startBackground" type="idref" value="startColor"/>
<object class="javax.swing.plaf.ColorUIResource" id="endColor">
<int>1</int>
<int>20</int>
<int>80</int>
</object>
<defaultsProperty key="Panel.endBackground" type="idref" value="endColor"/>
<painter method="panelBackground" idref="background"/>
</style>
<bind style="panel" type="region" key="Panel"/>

清單 8 展示了例子應用程序的定制繪畫類的 Java 代碼:

清單 8. 定制繪畫的 Java 代碼

public class BackgroundPainter extends SynthPainter
{
public void paintPanelBackground(SynthContext context,
Graphics g, int x, int y,
int w, int h)
{
Color start = UIManager.getColor ("Panel.startBackground");
Color end = UIManager.getColor("Panel.endBackground");
Graphics2D g2 = (Graphics2D)g;
GradientPaint grPaint = new GradientPaint(
(float)x, (float)y, start,
(float)w, (float)h, end);
g2.setPaint(grPaint);
g2.fillRect(x, y, w, h);
g2.setPaint(null);
g2.setColor(new Color(255, 255, 255, 120));
g2.setRenderingHint(
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
CubicCurve2D.Double arc2d = new CubicCurve2D.Double(
0, h/4, w/3, h/10, 66 * w, 1.5 * h, w, h/8);
g2.draw(arc2d);
g2.setRenderingHint(
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
}
}

更高級的設置

本節包含兩個超出登錄屏幕例子范圍的技術。在創建您自己的 Synth 外觀時 ,您可能發現這兩項技術很有用。

繪制非 Swing 組件

可以改變每個 Swing 組件的外觀這一點雖然很棒,但是還應該能夠改變其他 組件 —— 開發人員創建的用於填補 Swing 空缺的組件 —— 的外觀。在這種 情況下,<bind>標簽需要作出改變,以反映正在繪制的不是一個 Swing 組件。type屬性可以有兩種值:如果映射到一個 Swing 組件,則該值為 region ,如果映射到非 Swing 組件,則該值為 name。因此,如果將 <bind>標 簽變為 <bind style="mystyle" type="name" key="Custom.*"/>,則會改變每個類名以 Custom開始的組件(例 如,CustomTextField或 CustomLabel),使它們使用 mystyle式樣。

式樣的分層結構

除了在創建 XML 文件時使用 KISS 式樣之外,還可以構建分層次的一些式樣 ,並將這些式樣應用於組件中。清單 9 應該可以清楚地演示這一點。注意, Synth 使用最後定義的屬性來顯示組件。

清單 9. 分層結構的例子

<style id="base">
<color value="BLACK" type="BACKGROUND"/>
<state>
<font size="14"/>
</state>
</style>
<bind style="base" type="region" key=".*"/>
<style id="sublevel" clone="base">
<color value="RED" type="BACKGROUND"/>
</style>
<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 外觀。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved