青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

逛奔的蝸牛

我不聰明,但我會很努力

   ::  :: 新隨筆 ::  ::  :: 管理 ::

高級 Synth

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

Michael Abernethy, 軟件工程師, EMC

簡介: 本文將深入透視 Synth 外觀,它是 Java 5.0 中為 Swing 引入的最新內(nèi)容。通過為 Java UI 編程引入“皮膚”的概念,Synth 使開發(fā)人員可以為應(yīng)用程序創(chuàng)建和部署定制的外觀。軟件工程師 Michael Abernethy 將帶您從頭開始逐步構(gòu)建一個具有 synth 外觀的應(yīng)用程序,讓您充分了解 Synth 的概念。閱讀本文之后,您應(yīng)該可以在短時間內(nèi)創(chuàng)建具有專業(yè)外觀的 UI。

本文的標簽:  best_practicesswing外觀應(yīng)用開發(fā)

發(fā)布日期: 2005 年 2 月 01 日 
級別: 初級 
訪問情況 : 2692 次瀏覽 
評論: 0 (查看 | 添加評論 - 登錄)

平均分 4 星 共 10 個評分 平均分 (10個評分)
為本文評分

就在 Sun 一如既往地試圖“再次引入 Java Desktop”之際,Java UI 開發(fā)人員的抱怨之詞亦已表面化:要創(chuàng)建完全定制的外觀實在太難。這樣做不僅要花費太多的時間,并且 Swing UI 代碼的編寫和文檔的編制也極為不堪,常常是亂雜一氣,缺乏規(guī)劃。為了創(chuàng)建完整的外觀,開發(fā)人員需要繼承 Metal 外觀的 39 個類,或者繼承 Basic 外觀的 60 個類。誰想通過重寫整個包來改變應(yīng)用程序呈現(xiàn)外觀的方式呢?用 Swing 創(chuàng)建定制外觀有多難,通過下面的事實同樣可窺見一斑:在很多開發(fā)人員為開源項目添磚加瓦的時代,Internet 上可用的自定義 Swing 外觀幾乎是鳳毛麟角 —— 總共大約是 20 個,其中少數(shù)在 SourceForge.net 上(請參閱 參考資料)。

美麗只是膚淺的東西

進入 Synth,Sun 希望它能使應(yīng)用程序外觀的個性化過程變得容易。Synth 的目標很簡單 —— 讓開發(fā)人員不必編寫任何代碼就可以創(chuàng)建新的外觀。這似乎是個不錯的解決方案。程序員一般沒有突出的藝術(shù)才華,而圖形設(shè)計人員通常也不是 Java 編程專家。Synth 把對外觀的所有描述從代碼中分離出來,而將其放入外部的 XML 文件和圖像文件中,為上述問題提供了大快人心的解決之道。這種完全在外部文件中描述的外觀被稱作 皮膚(skin)

Sun 的皮膚概念并不是什么創(chuàng)新。例如,Winamp 有數(shù)百種皮膚,F(xiàn)irefox 也有幾十種皮膚,這些皮膚很容易創(chuàng)建,只需更改一個 XML 文件即可。想像一下,僅僅修改一個 XML 文件,就能快速、容易地為 Java 應(yīng)用程序創(chuàng)建一個外觀。再想想這樣一來的結(jié)果 —— 幾百個互不相同的 Swing 外觀。Java UI 開發(fā)人員當然有理由歡呼了。

本文將深入分析 Synth 外觀,向您展示創(chuàng)建一個完整的外觀或皮膚所需知道的一切。您會看到一個帶有示例皮膚的應(yīng)用程序,這個應(yīng)用程序使用了 Synth 所有重要的概念。然后,我會逐步剖析這個皮膚,在構(gòu)建 XML 文件的過程中,一一教會您 Synth 的各個概念。

本文最后一節(jié)將盡力回答開發(fā)人員關(guān)于 Synth 性能、bug 和缺陷以及 Synth 在省時方面的表現(xiàn)等種種問題。閱讀本文之后,您應(yīng)該會愿意擁護 Synth 作為外觀解決方案,并準備馬上使用它來創(chuàng)建自己的 Swing 外觀。

Synth 基礎(chǔ)

Synth 是一個 白板(tabula rasa)外觀 —— 一塊完全空白的畫布,表現(xiàn)為一個完全空白的面板(panel),只有在 XML 文件中定義了組件時,它才會顯示東西。一旦定義了組件,在應(yīng)用程序上設(shè)置 Synth 外觀就再容易不過了,如清單 1 所示:


清單 1. 設(shè)置 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)這道符咒,您可以快速地創(chuàng)建一個 XML 文件,并得到一個新的、可以運行的外觀。

考慮到 KISS 指令,我將首先介紹 Synth XML 文件的主要構(gòu)件 —— <style>標簽。<style>標簽包含描述一個組件的式樣的所有信息,例如顏色、字體、圖像文件、狀態(tài),以及一些特定于組件的屬性。雖然一個 <style>標簽可以描述多個組件,但構(gòu)建 Synth 文件的最簡便方法是為每個 Swing 組件創(chuàng)建一個式樣。

創(chuàng)建好式樣之后,便可以將式樣鏈接到一個組件。<bind>標簽通知 Synth 引擎將一個已定義的式樣鏈接到一個組件,如清單 2 所示。這樣的組合便完全創(chuàng)建了組件的新外觀。


清單 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"/>

關(guān)于 <bind>標簽,要注意的一點是:<bind>標簽中的 key屬性映射到 javax.swing.plaf.synth.Region類中的常量。Synth 引擎使用這些常量將式樣與一個實際的 Swing 組件鏈接。簡單的組件,例如 JButton和 JTextField,使用一個常量。有些更復(fù)雜的組件,例如 JScrollBar和 JTabbedPane,則有多個常量,用于不同的部分。

我建議您在更熟悉 Synth 格式并且能夠設(shè)置 XML 中的繼承模型之前,使用每個組件一種式樣(one-style-per-component)的設(shè)置。這種結(jié)構(gòu)雖然沒有利用所有 XML 的分層結(jié)構(gòu)功能,但它是最容易設(shè)置、編寫代碼和調(diào)試的。

在處理 Synth XML 文件時,還有一點很重要,并不是任何形式都是合法的。如果有輸入錯誤,或者在 XML 中使用了不正確的屬性,這些錯誤只有當外觀裝載期間拋出一個運行時異常時才能發(fā)現(xiàn)。解決方法:在將 XML 文件發(fā)布給客戶之前,對其進行測試。

Demo 應(yīng)用程序

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

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


圖 1. 具有 Ocean 外觀的 Demo 應(yīng)用程序 
Ocean 外觀 

圖 2. 具有 Synth 外觀的 Demo 應(yīng)用程序
Synth 外觀 

更改顏色和字體

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

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

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

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

  • type 描述文件應(yīng)該設(shè)置哪個區(qū)域的顏色。選擇有BACKGROUNDFOREGROUNDTEXT_FOREGROUNDTEXT_BACKGROUND和 FOCUS

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

  • name :字體的名稱(例如,VerdanaArial)。

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

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

最后,通過使用 .* wildcard,將這個式樣綁定到應(yīng)用程序中的每個組件,而不是將其綁定到每個 JLabel和每個 JButton。這個通配符告訴 Synth 外觀為每個組件指定一個默認的 white Aharoni 字體。清單 3 展示了用于設(shè)置組件字體和顏色的完整 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邊框不是常規(guī)外觀的單像素矩形邊框。可以使用一個圖像來創(chuàng)建這些邊框。這不是我們所熟悉的概念 —— 圖像用在 button 和 label 中已經(jīng)有些時候了 —— 但您可以想像在哪些地方會出問題。如何知道光標移動到什么地方,如何顯示文本,如何創(chuàng)建不同大小的文本域?這些問題可以通過 圖像拉伸(image stretching)的概念來解決。一個圖像文件必須描述應(yīng)用程序中文本域各個邊的長度,因此需要有一種方式來告訴 XML 文件如何適當?shù)乩靾D像,以及如何處理常規(guī)的 textfield活動(carat 和文本控制)。

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


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

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

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

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

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

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

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

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

清單 4 展示了用于裝載圖像的 XML 代碼。注意 sourceInsets如何確保圖像只有適當?shù)牟糠直焕臁?/p>
清單 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"/>

處理不同的狀態(tài)

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

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


圖 4. DEFAULT 狀態(tài)下的 Cancel 按鈕
Default 狀態(tài) 

圖 5. MOUSE_OVER 狀態(tài)下的 Cancel 按鈕
Mouse over 狀態(tài) 

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

清單 5 展示了用于處理 demo 應(yīng)用程序狀態(tài)的 XML。注意每種狀態(tài)是如何定義不同的圖像和文本顏色的。


清單 5. 處理狀態(tài)
            <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"/>

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

處理特定于組件的屬性

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

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

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


清單 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 來實現(xiàn)這種背景似乎有些別扭,坦白地說,真是這樣。但這樣我便有機會展示 Synth,不限制您在 UI 設(shè)計中只使用圖像和簡單的顏色。您可以使用它來畫任何東西。

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

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

  • class :將創(chuàng)建的類的全名。
  • id :用于在 XML 文檔中引用這個類實例的 ID 名。

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

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

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

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

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

清單 7 展示了在例子應(yīng)用程序中使用定制 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 展示了例子應(yīng)用程序的定制繪畫類的 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);
            }
            }

更高級的設(shè)置

本節(jié)包含兩個超出登錄屏幕例子范圍的技術(shù)。在創(chuàng)建您自己的 Synth 外觀時,您可能發(fā)現(xiàn)這兩項技術(shù)很有用。

繪制非 Swing 組件

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

式樣的分層結(jié)構(gòu)

除了在創(chuàng)建 XML 文件時使用 KISS 式樣之外,還可以構(gòu)建分層次的一些式樣,并將這些式樣應(yīng)用于組件中。清單 9 應(yīng)該可以清楚地演示這一點。注意,Synth 使用最后定義的屬性來顯示組件。


清單 9. 分層結(jié)構(gòu)的例子
            <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 復(fù)制了整個式樣。然后,您可以覆蓋所需的任何特定屬性。

檢驗 Synth 的性能、可靠性和效率

至此,您已經(jīng)看到如何創(chuàng)建用于 Synth 的 XML 文件,以及如何通過更改字體、更改顏色和添加圖像來創(chuàng)建定制的外觀,但對于 Synth 可能還有些疑問。如果您使用 Swing 已經(jīng)有一段時間,那么我可以肯定,您首先想到的是性能問題。我設(shè)計了一些性能測試,這些測試表明,Synth 不會令您的 UI 慢如蝸牛。為了調(diào)查您可能看到的問題(并討論我在使用 Synth 時已經(jīng)碰到過的一些問題),我查看了 Java Bug Parade (請參閱 參考資料)。最后,我將回答最重要的問題 —— Synth 真的可以節(jié)省您的時間嗎?

裝載那么多圖像會不會使 Synth 變得更慢?

為了回答這個問題,我創(chuàng)建了兩個測試,并讓您更深切地體會 Synth 在性能方面與其他外觀的比較。第一個測試將測試示例登錄應(yīng)用程序的裝載時間。該測試裝載 6 個 Synth 圖像,并將這個裝載時間與一個開發(fā)人員可能創(chuàng)建的一般屏幕的裝載時間進行比較。第二個測試是關(guān)于裝載時間的壓力測試 —— 一個幀中有 100 多個組件。

兩個測試都將測試 Ocean 和 Motif 外觀的裝載時間,以便進行比較。為了公正起見,我在三種機器上運行了這兩個測試 —— 一種是安裝 Windows XP 的手提電腦,一種是 SuSE Linux box,還有一種是 Red Hat Linux box。結(jié)果顯示在表 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 慢一點點。但是請注意,登錄屏幕與壓力測試會比裝載更慢一些。乍一看來,這似乎很奇怪,但如果仔細研究,便可以發(fā)現(xiàn)起因。壓力測試沒有裝載復(fù)選框中所使用的圖像,而登錄屏幕卻裝載了這些圖像。據(jù)此可以下結(jié)論,在 Synth 外觀中使用的每個附加圖像增加了裝載時間。與含有兩個使用兩種不同圖像的組件的應(yīng)用程序相比,使用相同圖像的 100 個組件裝載起來要更快一些。減少所使用圖像的數(shù)量可以提高 Synth 裝載時間方面的性能。

Synth 是不是像 Swing 一樣,在第一次發(fā)布時滿是 bug ?

根據(jù) Sun Java 開發(fā)者網(wǎng)站上 Bug Parade 的評判,Synth 看上去是一個比較干凈、沒有 bug 的產(chǎn)品。然而,沒有哪個軟件是完美的。Synth 曾經(jīng)有 125 個 bug,這與 Synth 處理 JTabbedPane的方式不成比例。因此,如果您經(jīng)歷到一些問題,不要感到驚訝。然而,根據(jù) Sun 的辯護,這些缺陷都處于“關(guān)閉(Closed)”狀態(tài)。但通常的情況是,如果以前存在某些問題,那么這些問題在將來也很可能會出現(xiàn)。

雖然 bug 數(shù)據(jù)庫為 Synth 賦予了一個相對干凈的形象,我在處理登錄屏幕的時候還是碰到一些問題。我第一次嘗試更改 JPanel背景顏色時遭到失敗。我創(chuàng)建了一個特定于 JPanel的式樣,并將其綁定到所有 JPanel,但這樣行不通。而當我決定使用自己的定制 painter 時,事情就解決了。

一個更大的問題是當狀態(tài)改變時對組件進行重新繪制。在處理按鈕及其狀態(tài)時,我發(fā)現(xiàn),按鈕上的文本不能正確地改變顏色。當初始化時,作為默認顏色的白色沒有如期顯示,并且直到觸發(fā)了狀態(tài)變化之后才出現(xiàn),然后就被重新設(shè)置為默認顏色。如果仔細研究關(guān)于 Synth 的文檔,就可以發(fā)現(xiàn)這個小花絮:“雖然可以為每種狀態(tài)提供不同的字體,但在一般情況下,當組件的狀態(tài)變化時,組件不會重新生效,所以,如果您試圖為不同狀態(tài)使用有明顯不同大小的字體時,有可能會遇到字體大小的問題”。聽起來似乎它們遇上了試圖讓 Synth 使用老的 Swing 代碼的問題。因此,如果要在狀態(tài)改變時更改字體,那么要小心。

Synth 看上去的確很少有 bug。但如果隨處出點小問題,那些本應(yīng)該行得通的代碼就會行不通,我不會對此感到驚訝。不過,變通的辦法不難找到。對于在工作中碰到的每個問題,我總能找到一個變通的辦法。

利用 Synth 可以創(chuàng)建出完全專業(yè)的外觀嗎?

回答是肯定的。Java 1.4 中發(fā)布的 GTK+ 和 Windows XP 外觀就完全是用 Synth 創(chuàng)建的。(那時它不是一個已公布的 API。) 所以這方面顯然沒有問題。

用 Synth 創(chuàng)建一個完整的外觀比用 Java 代碼編寫這樣的外觀要快多少?

這很容易計算。這兩種方法各自都包含兩個步驟:

  1. 創(chuàng)建外觀,這通常是由圖形設(shè)計人員負責(zé)的工作。
  2. 將圖形界面轉(zhuǎn)化成代碼。

不管是用 Java 編寫代碼還是使用 Synth,圖形界面設(shè)計這部分工作所花的時間是相同的。根據(jù)我創(chuàng)建定制外觀的經(jīng)驗,我估計為一個應(yīng)用程序創(chuàng)建一個完整的外觀需要兩個圖形設(shè)計人員兩周的時間。也就是說,圖像設(shè)計工作需要 4 人一周(person-week)的人力。

通常,根據(jù)我的經(jīng)驗,通過類繼承的方式將圖形界面翻譯成立即可用的外觀需要三個 Java 編程人員花大約兩個月的時間。也就是說,編寫 Java 代碼需要 6 個人一個月(person-month)的人力。加上圖形界面設(shè)計工作,通過重寫 UI 類,用 Swing 創(chuàng)建一個完全定制的外觀總共需要 7 個人一個月的工作量。這些數(shù)據(jù)有助于您明白為什么 Internet 上可供下載的定制外觀是那么少。

通過將圖形界面轉(zhuǎn)換成一個 XML 文件,Synth 可以節(jié)省大量的時間。通過 Java 編程創(chuàng)建外觀需要 6 個人一個月的工作量,而一個開發(fā)人員將圖形界面轉(zhuǎn)換成 Synth XML 文件只需兩個星期。用 Synth 創(chuàng)建完整外觀所需的工作量減少到僅僅 6 個人一周的工作量 —— 通過使用 Synth 節(jié)省了超過 5 個月的時間。對于一個由兩個圖形設(shè)計師和兩個程序員組成的團隊,在短短三個星期內(nèi)便可以創(chuàng)建出一個完整的 Synth 外觀。

結(jié)束語

Synth 將皮膚的概念引入到 Swing 中。相對于傳統(tǒng)的用 Java 代碼編寫定制外觀的方法,Synth 最大的優(yōu)勢是節(jié)省時間。一個完整的 Swing 外觀可以在不到一個月的時間里完成,這比用 Java 語言編程的方法要快 5 倍。對于有干勁的開發(fā)人員,在用 Java 代碼編寫一個外觀的時間里,他可以創(chuàng)建 5 個 Synth 外觀。

然而,Synth 并非毫無瑕疵。通過編寫 Java 代碼覆蓋 Swing 外觀,可以同時改變應(yīng)用程序的外觀和 感覺。而 Synth 只允許改變應(yīng)用程序的外觀。這是一個很大的不同之處。外觀是指應(yīng)用程序中使用的顏色、字體和圖形。另一方面,感覺則對應(yīng)于應(yīng)用程序在交互期間展現(xiàn)出來的行為 —— 這里指單擊一下鼠標右鍵,那里按下一個鍵。例如,如果您想改變一個 JList的行為,希望通過單擊鼠標左鍵選中條目,然后再通過單擊鼠標右鍵來刪除條目,那么用 Synth 是無法做到這些的。您需要為新的外觀編寫 Java 代碼。Synth 實際上應(yīng)該稱為一種新的 Swing 外觀,而不是一種普通外觀。通過 Synth 可以快速改變 UI 的外觀,但 UI 的感覺永遠都是默認的 Swing 感覺。

當然,如果您想通過為應(yīng)用程序提供新的外觀來使之整潔漂亮,或者渴望看到比令人討厭的 Metal 外觀(謝天謝地,在 Java 5.0 中它已成為歷史)更好的 Swing 應(yīng)用程序外觀,那么 Synth 是很好的一個選擇。它不存在性能問題,并且看上去 bug 也很少。Sun 已經(jīng)表示,通過發(fā)布 GTK+ 外觀,用 Synth 可以創(chuàng)建完整的外觀。

令人吃驚的是,Synth 文檔和實例現(xiàn)在還很少。閱讀本文之后,對于 Synth 的工作原理您應(yīng)該有一個更深的理解,并且能夠使用一個組件一個樣式標簽(one-style-tag-per-one-component)的設(shè)計來生成一個完整的 Synth XML 文檔。Synth 的繼承和分層模型為創(chuàng)建 style 標簽提供了更強大的方法,但沒有它們?nèi)匀豢梢詣?chuàng)建完整的外觀。理想情況是:隨著對 Synth 認識的加深,Swing UI 社區(qū)將出現(xiàn)皮膚數(shù)量的大爆炸。有了數(shù)百個可供選擇的外觀,通常那些加在 Swing 應(yīng)用程序身上的“長相恐怖”、“丑陋”之類的責(zé)罵之詞也將永遠消失。


下載

名字大小下載方法
synth.jar 21 KB HTTP

關(guān)于下載方法的信息


參考資料

  • 您可以參閱本文在 developerWorks 全球站點上的 英文原文

  • 單擊本文頂部或底部的 Code圖標(或查看 下載小節(jié)),以便下載本文中所使用的代碼示例。

  • 請務(wù)必參閱 Synth Javadoc

  • Synth File Format文檔對 Synth XML 文件中所有可能出現(xiàn)的情況提供了完整的介紹。

  • Synth Component Specific Properties文檔列出了在 XML 文件中可以設(shè)置的 100 多個特定于組件的屬性。

  • Region類文檔列出了所有 Swing 組件以及可以在 Synth XML 文件中改變的部分組件。

  • SynthPainter類文檔列出了在 imagePainter和 painter標簽中可以描述的所有函數(shù)。

  • SourceForge 上提供的定制 Swing 外觀包括 Liquid、 NapkinoyoahaSkinGTK+ PluggableVira和 Office外觀。

  • John Zukowski 撰寫的 Taming Tiger系列中的文章“Ocean and Synth meet Metal”(developerWorks, 2004 年 8 月)探索了 Java 5.0 中的新外觀 Ocean 和 Synth。

  • Scott Violet 所著的“The Synth Look and Feel”是 Sun 關(guān)于 Synth 的最初表述,時間要追溯到 2004 年早期 Synth 剛被引入之際。

  • 請參閱可搜索獲得的 Java Bug Database(即 Java Bug Parade)。

  • 請參閱 Michael Abernethy 關(guān)于 Swing 和 UI 開發(fā)的其他文章。“用 TableModel Free 框架簡化 Swing 開發(fā)”(developerWorks, 2004 年 8 月)介紹了 TableModel Free 框架,該框架消除了結(jié)合使用 TableModels 和 Swing JTables 的需要。“Go state-of-the-art with IFrame”(developerWorks, 2004 年 3 月)展示了如何使用 IFrame 架構(gòu)將 JFrame 窗口轉(zhuǎn)化成定制的應(yīng)用程序窗口。

  • IBM alphaWorks 上的 IBM Reflexive User Interface Builder(RIB)是一個應(yīng)用程序和工具箱,它使您可以為基于描述性 XML 文檔的 Java Swing 和 Eclipse SWT 構(gòu)造和交付 GUI。“Reflexive User Interface Builder 簡介”(developerWorks, 2004 年 8 月)探索了基于 Java 2 Swing 框架的一些 RIB 例子。

  • 在 developerWorks Java 技術(shù)專區(qū)可以找到關(guān)于 Java 編程的各個方面的文章。

  • 請參閱 Developer Bookstore,以獲得技術(shù)性書籍的完整清單,其中包括數(shù)百篇 Java 相關(guān)主題的書籍。

關(guān)于作者

Michael Abernethy

Michael Abernethy 目前是 WebSphere 系統(tǒng)管理功能性測試團隊的負責(zé)人。之前,他在 WebSphere Services 團隊工作了 4 年,一直在 WebSphere 上編寫、部署應(yīng)用程序。在業(yè)余時間里,他還參與了 Swing 和 UI 開發(fā)。您可以通過 Michael 的郵箱 mabernet@us.ibm.com 與他聯(lián)系。

為本文評分

平均分 4 星 共 10 個評分 平均分 (10個評分)

1 星1 星
2 星2 星
3 星3 星
4 星4 星
5 星5 星

評論

請 登錄 或 注冊 后發(fā)表評論。

注意:評論中不支持 HTML 語法


剩余 1000 字符




在檢索評論時出錯,請稍后刷新。

標簽

Help
使用搜索文本框在 My developerWorks 中查找包含該標簽的所有內(nèi)容。熱門標簽 顯示了特定專區(qū)最受歡迎的標簽(例如 Java technology,Linux,WebSphere)。我的標簽 顯示了特定專區(qū)您標記的標簽(例如 Java technology,Linux,WebSphere)。

熱門標簽

熱門標簽結(jié)束

我的標簽

要訪問我的標簽,請登錄

查看熱門標簽


我的標簽結(jié)束

更多更少

查看方式 | 列表


From: http://www.ibm.com/developerworks/cn/java/j-synth/

posted on 2011-12-03 09:57 逛奔的蝸牛 閱讀(1153) 評論(0)  編輯 收藏 引用 所屬分類: Java
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美高清hd18日本| 欧美国产日本在线| 狠狠色狠狠色综合日日小说| 牛牛国产精品| 久久综合色播五月| 另类av一区二区| 模特精品裸拍一区| 欧美α欧美αv大片| 嫩草影视亚洲| 亚洲国产婷婷香蕉久久久久久| 久久九九精品| 欧美国产三区| 日韩视频在线观看国产| 亚洲少妇诱惑| 久久九九久精品国产免费直播| 激情av一区| 在线不卡亚洲| 亚洲卡通欧美制服中文| 这里是久久伊人| 久久久久久夜精品精品免费| 欧美成在线观看| 一区二区三区你懂的| 欧美在线精品一区| 欧美激情第五页| 国产日产亚洲精品| 亚洲精品一区二区三区不| 一区二区三区高清视频在线观看| 先锋影音网一区二区| 欧美日本国产在线| 亚洲一区久久| 久久一区二区三区av| 欧美日韩精品高清| 韩国一区二区三区在线观看| 99热这里只有成人精品国产| 欧美一区激情| 亚洲三级毛片| 久久免费国产精品1| 国产精品大全| 亚洲精品一区二区三区蜜桃久| 欧美影院视频| 99国产精品视频免费观看| 久久免费的精品国产v∧| 国产精品户外野外| 亚洲精品欧洲| 男女av一区三区二区色多| 亚洲伊人色欲综合网| 欧美激情综合网| 在线欧美日韩| 久久亚洲私人国产精品va媚药| 一本色道久久综合亚洲精品婷婷| 老巨人导航500精品| 国产亚洲精品一区二区| 亚洲男同1069视频| 日韩视频永久免费| 欧美日韩国产在线播放网站| 亚洲国产精品久久久久秋霞影院| 久久九九热re6这里有精品| 亚洲特黄一级片| 欧美视频一区二区三区| 一区二区三区毛片| 亚洲欧洲一区二区天堂久久| 久久综合电影| 亚洲第一福利社区| 欧美大片在线观看| 欧美成人午夜剧场免费观看| 亚洲国产精品精华液2区45| 欧美承认网站| 欧美另类高清视频在线| 一本一本久久a久久精品综合妖精| 亚洲国产高清在线观看视频| 蜜桃av一区| 久久精彩视频| 在线观看亚洲精品| 亚洲电影av在线| 欧美国产一区二区| 99国产精品99久久久久久| 亚洲欧洲另类| 欧美日韩国产综合在线| 亚洲一区二区三区在线播放| 制服丝袜亚洲播放| 国产亚洲一区在线| 欧美激情网站在线观看| 欧美激情一区二区三区在线视频观看 | 欧美三区免费完整视频在线观看| 亚洲精品一区二区三区婷婷月| 亚洲精品久久| 99re6热在线精品视频播放速度| 欧美国产综合一区二区| 麻豆精品在线播放| 99国内精品| 亚洲欧美日韩在线| 在线观看一区二区视频| 亚洲国产日韩一级| 国产精品福利片| 蜜臀av国产精品久久久久| 欧美激情第4页| 久久精品国产99国产精品| 美日韩丰满少妇在线观看| 亚洲尤物视频网| 久久久精品久久久久| 一本久道久久综合中文字幕| 亚洲一线二线三线久久久| 在线观看中文字幕不卡| 99国产成+人+综合+亚洲欧美| 国产日韩欧美在线播放| 亚洲福利视频专区| 国产情人综合久久777777| 亚洲欧洲另类国产综合| 国语对白精品一区二区| 夜夜嗨av一区二区三区| 在线精品福利| 新狼窝色av性久久久久久| 99riav国产精品| 久久精品一本| 欧美一级黄色网| 欧美伦理a级免费电影| 久久一二三四| 国产精自产拍久久久久久蜜| 亚洲国产精品123| 国产日韩精品一区二区| aa级大片欧美三级| 99精品久久久| 久久综合九色99| 久久久水蜜桃av免费网站| 欧美午夜精品久久久久久孕妇| 欧美高清在线精品一区| 韩日精品中文字幕| 午夜视频在线观看一区| 在线亚洲精品| 欧美日韩一区二区免费视频| 欧美成人精品激情在线观看| 国产一区二区中文| 亚洲欧美高清| 久久电影一区| 国产亚洲网站| 久久国产一区二区| 久久综合久久久久88| 狠久久av成人天堂| 欧美一区二区三区免费视| 欧美亚洲视频在线观看| 国产精品乱人伦中文| 在线视频日韩| 午夜精品久久久久久| 国产精品拍天天在线| 亚洲香蕉伊综合在人在线视看| 亚洲主播在线| 国产欧美在线| 久久久久久网址| 亚洲电影观看| 在线亚洲高清视频| 国产精品成人午夜| 亚洲欧美国产日韩中文字幕| 国产精品久久久久久久久久久久| 亚洲免费综合| 国产精品日日摸夜夜摸av| 亚洲一区二区免费看| 性8sex亚洲区入口| 国产午夜精品麻豆| 久久久av网站| 亚洲黑丝在线| 亚洲一区二区三区视频| 国产精品专区一| 久久久国产一区二区| 亚洲电影在线免费观看| 一区二区三区高清不卡| 国产精品剧情在线亚洲| 久久国产黑丝| 亚洲精品之草原avav久久| 亚洲男人的天堂在线观看| 一区二区三区在线观看国产| 欧美**人妖| 亚洲免费视频中文字幕| 美女精品自拍一二三四| 亚洲视频精品| 精品999在线播放| 欧美久色视频| 久久久久国产精品厨房| 亚洲美女诱惑| 久久免费一区| 亚洲视频导航| 亚洲激情网站| 国产欧美日韩亚州综合| 欧美国产精品久久| 久久丁香综合五月国产三级网站| 亚洲国产片色| 可以看av的网站久久看| 亚洲欧美国产77777| 亚洲精品在线观看免费| 国产麻豆91精品| 欧美久久久久免费| 葵司免费一区二区三区四区五区| 亚洲一区二区三区乱码aⅴ| 亚洲国产日韩欧美一区二区三区| 久久大逼视频| 亚洲欧洲99久久| 亚洲视频1区| 亚洲美女电影在线| 亚洲福利视频专区| 精品成人一区二区三区| 国产精品一区二区久久国产|