在1.4.2 版之前,J2SE包括了3種可插式look-and-feel (PLAF)設計:
Windows:模仿 Windows 2000 操作系統(由於許可限制,PLAF只能在Windows平台下使用)。
Motif:模仿Motif應用程序。
Metal:使用它自己的獨立於任何現有操作系統的look-and-feel。
J2SE 1.4.2 提供了兩種附加的look-and-feel 設計。John Zukowski在他的 Merlin的魔力 專欄中的“J2SE 1.4.2 gets two new look-and-feel designs” 一文(參見 參考資料)中描述了這兩種設計。這兩種新的look-and-feel設計是:
Windows XP:模仿Windows XP操作系統(只能用在Windows平台下)。
GTK+:模仿Linux下的GTK應用程序。
感覺好不如看起來好
對於大多數人來說,應用程序的look-and-feel只不過是一種偏好和欣賞。但是在某些情況下,有必要定制應用程序的look-and-feel,使其使用特定的字體、顏色模式或圖標。例如,有些弱視用戶常常要求look-and-feel在文本與背景之間具有高對比度,同時還要有大的字體和圖標。"IBM Java Accessibility Checklist" (參見 參考資料)規定,一個應用程序中的所有用戶界面對象都必須支持高對比度設置。
Java 平台早期的版本對顏色和字體的偏好設置的支持不是很好。從J2SE 1.4開始,尤其是隨著J2SE 1.4.2中新的Windows XP 和 GTK look-and-feel設計的引入,用戶現在可以配置他們想要的look-and-feel設計。Windows look-and-feel試圖使用Windows平台底層的顏色和字體模式,而GTK look and feel則使得Linux用戶能夠通過定義一些腳本來定制look-and-feel。
乍一看來,“本地的” look-and-feel 設計的改進使得Metal look and feel失去了作用。然而在有些場合中,Metal look-and-feel(或者其定制版本)仍然比較有用。例如:
如果您需要的是能夠在任何平台下運行,並且即使是被一個未簽名的applet使用時也是可定制的這樣一種look-and-feel。
如果您需要更多其他look-and-feel設計不能提供的定制能力。
如果您使用的是Java平台的一個早期版本,而這種版本最近的改進不可用。
本文將解釋如何修改Metal look-and-feel,使其使用特定的字體和顏色模式。您還將學習如何修改用於繪制窗口小部件(例如復選框、單選按鈕、樹以及文件對話框)的圖標。
首先我將解釋如何重載用於look-and-feel的顏色和字體。接著我們將看看如何修改標准窗口小部件所使用的圖標。最後,我們將看一個新look-and-feel的實例,在這個實例中您可以在一個文本文件中定義對顏色、字體和圖標大小的設置。以後您就可以使用我們的例子來創建高對比度的look-and-feel。
重載 Metal look and feel —— 修改顏色和字體
javax.swing.plaf.metal.MetalLookAndFeel 類是 Metal look and feel的主類。這個類的Java API 文檔(參見 參考資料)表明,這個類中定義的大部分方法都是getter方法,用以返回畫Swing框架中提供的不同窗口小部件時所用的顏色和字體。然而,這些getter方法返回值的任務並不是直接在這個類中實現的,而是委托給了另一個類,這個類叫做一個 主題(theme)。主題惟一的作用就是提供要使用的顏色和字體的值。
Metal look and feel 使用一種可插式主題體系結構。這種look and feel 本身 ( javax.swing.plaf.metal.MetalLookAndFeel ) 定義了窗口小部件的外觀以及它們對用戶交互的反應,而主題則定義在繪制窗口小部件時應該使用的顏色和字體。您可以通過創建一個新的繼承 javax.swing.plaf.metal.MetalTheme 的類來定義一種新的主題。
圖 1 和 圖 2 顯示了來自SwingSet演示程序的兩個屏幕截圖,這個演示程序是隨JSDK一起提供的。這兩個圖演示了不同的主題是如何改變一個應用程序的外觀的,而且,這裡的應用程序使用的是同一個look-and-feel。
圖 1. 默認的主題
圖 2. 高對比度主題
因此,定制Metal look and feel 很容易,只需:
創建一個新的擴展 javax.swing.plaf.metal.MetalTheme 的類,或者創建 javax.swing.plaf.metal.MetalTheme 的默認實現 javax.swing.plaf.metal.DefaultMetalTheme (參見 參考資料部分中給出的Java API文檔的參考提示)。
重載這個主題類的 getXXXFont() 或者 getXXXColor() 方法,使這兩個方法能返回在新主題中需要用到的字體或顏色。
通過調用 MetalLookAndFeel.setCurrentTheme(theme) 靜態方法設置Metal look and feel中的新主題。
javax.swing.plaf.metal.MetalTheme 的Java API文檔(參見 參考資料)表明,您可以重載大約50個不同的方法,在一個細粒度的程度上定義必須使用的顏色和字體。不幸的是,大部分的這些方法都沒有相應的文檔,這使得測試每個方法以檢查它對用戶界面的影響這樣的一項任務相當煩人。
幸運的是,您通常不需要重載所有這些方法便可以得到一個可接受的結果――如果 vax.swing.plaf.metal.MetalTheme 提供了眾多的方法,那麼它的默認實現 javax.swing.plaf.metal.DefaultMetalTheme 也會以一致的方式實現大部分的這些方法,這樣一來這些方法就會返回以下方法中某個方法的結果:
getBlack()
getWhite()
getPrimary1()
getPrimary2()
getPrimary3()
getSecondary1()
getSecondary2()
getSecondary3()
getControlTextFont()
getMenuTextFont()
getSubTextFont()
getSystemTextFont()
getUserTextFont()
getWindowTitleFont()
因而,繼承 javax.swing.plaf.metal.DefaultMetalTheme 和重載這8種顏色及6種字體通常就足以獲得一個一致的新主題。
不用硬編碼這些方法(Java平台提供的主題中就是硬編碼的),相反,一個好主意是實現一個能返回在外部資源文件中指定的顏色和字體的通用的主題。通過這種方式,我們可以輕易地定義一個新主題――我們只需要使用任何文本編輯器編輯一些值。
修改圖標
在某些情況下,可能還需要修改look and feel所使用的一些圖標和圖形資源。例如,您可能想修改復選框和單選按鈕所使用的圖標以便繪出它們的狀態,或者使用其他的圖標來繪制文件夾和樹組件的節點。
例如,如果您希望某個look and feel帶有大號字體,那麼就需要修改圖標。復選框和單選按鈕所使用的圖標的尺寸應該與它們的字體相適應。如果弱視用戶不能辨認某個選框是否被選中,那麼即使是帶有大字體的復選框對他(她)來說也是毫無用處的,因為其圖標的尺寸沒有改變。
圖3 顯示了一個高對比度、大字體的但是圖標的尺寸沒有改變的主題的例子。您可以看到字體大小和圖標尺寸之間的不協調。
圖 3. 一個高對比度、大字體但是沒有調整圖標尺寸的主題
不幸的是,在一個主題中圖標是不能修改的。因此,如果我們想重載Metal look and feel中使用的圖標,我們就必須使用其他的技術。
Metal look and feel將一系列要使用的圖形化資源(顏色、字體和圖像)存放在一個 javax.swing.UIDefaults 對象中,這個對象基本上就是一種hash表。不同窗口小部件所需的每個圖像都被該look and feel以特定的鍵(key)存放在這個表中,以便於檢索。這同時也意味著如果您知道某一特定圖像是存放在哪個鍵之下的,那麼您就可以通過將另一個圖像存放在同一個鍵下來替換那個圖像。
讓我們看看Metal look and feel如何初始化包含了圖形化資源的這個表。
當look and feel被創建時,它首先實例化一個空的 UIDefaults 對象,這個對象可以通過以下方法來填充內容:
initClassDefaults(UIDefaults)
initComponentDefaults(UIDefaults)
initSystemColorDefaults(UIDefaults)
這些方法中每一個方法都是由該look and feel本身連續地調用的。這些方法連續地將圖形化資源(不管是顏色、字體還是圖像)存入 UIDefaults 表中惟一的鍵之下。
要了解更多細節,參見 javax.swing.plaf.MetalLookAndFeel 類的API 文檔(參見 參考資料)。圖像的初始化是在 initComponentDefaults(UIDefaults )中進行的。通過重載這個方法,您可以替換在look and feel中用到的任何標准圖像。
不幸的是,存放圖標時所參考的鍵沒有相應的文檔,但是 javax.swing.plaf.MetalLookAndFeel 類的源代碼可以提供這些信息。表 1顯示了用於引用Metal look and feel中圖標的現有鍵的列表:
表 1. 用於引用Metal look and feel中圖標的鍵
CheckBox.icon InternalFrame . closeIcon RadioButton.icon InternalFrame.maximizeIcon InternalFrame.icon InternalFrame.iconifyIcon InternalFrame.iconifyIcon InternalFrame.minimizeIcon FileView.directoryIcon Menu.checkIcon FileView.fileIcon Menu.arrowIcon FileView.computerIcon MenuItem.checkIcon FileView.hardDriveIcon MenuItem.arrowIcon FileView.floppyDriveIcon CheckBoxMenuItem.checkIcon FileChooser.detailsViewIcon CheckBoxMenuItem.arrowIcon FileChooser.homeFolderIcon RadioButtonMenuItem.checkIcon FileChooser.listViewIcon RadioButtonMenuItem.arrowIcon FileChooser.newFolderIcon Tree.openIcon FileChooser.upFolderIcon Tree.closedIcon Slider.horizontalThumbIcon Tree.leafIcon Slider.verticalThumbIcon Tree.expandedIcon InternalFrame.icon Tree.collapsedIcon InternalFrame.paletteCloseIcon
縮放圖標
與隨Java平台一起交付的其他 look-and-feel設計不同,Metal look and feel並不使用GIF文件來繪制它的圖標。相反,它是通過一個名為 avax.swing.plaf.metal.MetalIconFactory 的工廠類來動態地創建圖標的。對於表 1 中列出的每一個鍵,它都提供一個相應的 getXXXIcon() 方法,用以繪制 矢量圖標。
利用一個工廠創建的矢量圖標有一個好處,那就是它們可以使用當前主題所定義的顏色,而不是預定義的顏色。因為這種圖標是矢量的,通常可以在不影響質量的情況下改變其大小。不幸的是,除了4個圖標外,在 MetalIconFactory 中沒有哪個方法會接收一個可以定義圖標大小的參數。因此,定義圖標大小的惟一的方法就是構建一個全新的圖標工廠。
幸運的是,對這個問題並非無計可施。您可以創建一個實現 javax.swing.Icon 接口的類,然後將一個現有的圖標以及縮放比例作為參數傳給這個類的構造函數,再用 java.awt.Graphics2D API繪出該圖標的一個新版本,在這個新版本中,其大小已發生了變化,其格式是位圖圖像格式(參見清單1)。當然,這意味著當一個圖標被放大時,該圖標的質量會有所損失。不過,這種方法實現起來比構建一個全新的圖標工廠要容易得多。而且,對於像復選框和單選按鈕這樣的一些簡單的圖標,經放大後其質量依然是可以接受的。
清單 1. 一個圖標放大器
/** A class to create a magnified version of an existing icon */
protected class MagnifiedIcon implements Icon {
private Icon icon ;
private double factor ;
public MagnifiedIcon(Icon icon, double factor) {
this.icon = icon ;
this.factor = factor ;
}
public int getIconWidth() {
return (int)(icon.getIconWidth()*factor) ;}
public int getIconHeight() {
return (int)(icon.getIconHeight()*factor) ;}
public void paintIcon(Component c, Graphics g, int x, int y) {
Graphics2D g2d = (Graphics2D)g.create() ;
g2d.translate(x,y);
g2d.scale(factor, factor);
icon.paintIcon(c,g2d,0,0);
g2d.dispose();
}
}
一個可定制的、高對比度的look and feel
清單 2 顯示了基於Metal look and feel以及為提供可定制的、高對比度的look and feel而創建的顏色模式的一種通用look and feel的源代碼。(從 參考資料下載源代碼)
第9行到第16行是裝載定義了該look and feel的一些屬性的外部資源文件。 這幾行代碼建立了一個定制的主題,該主題的顏色和字體是以外部文件定義的。
第18行到第20行重寫了 MetalLookAndFeel 的一些標准方法,以便將該look and feel的名稱、描述和ID也放在外部資源文件中定義。
第22行到第53行修改了該look and feel的UIDefaults,以便通過在外部資源文件中定義的一個縮放比例來放大標准圖標。真正的放大工作是由 MagnifiedIcon 這個內部類來做的(第95行到第113行)。
第56行到第92行是這個定制的主題的實現。這些代碼首先從資源文件中讀出要使用的字體的名稱和大小(第64行到第70行)。然後重寫 DefaultMetalTheme 的getter方法,以便使用在外部資源文件中定義的顏色和字體。
清單3顯示了用於Black on White Look and Feel, Large Fonts的外部資源文件。這個look and feel所使用的字體大小被設置為30(第5行),圖標被放大到初始大小的250%(第3行),基本顏色則被設置為黑色和白色(第6行到第15行)。
清單 3. HighContrastLAF.properties:白背景,黑文本
1 name = High Contrast Look And Feel
2. description = Black on white, large fonts
3. iconMagnificationFactor = 2.5
4. fontName = Dialog
5. fontSize = 30
6. backgroundColor = FFFFFF
7. foregroundColor = 000000
8. primaryColor1 = 000000
9. primaryColor2 = FFFFFF
10. primaryColor3 = FFFFFF
11. secondaryColor1 = 000000
12. secondaryColor2 = C0C0C0
13. secondaryColor3 = FFFFFF
14. selectionForeground = FFFFFF
15. selectionBackground = 000000
圖 4 顯示了這個look and feel的屏幕截圖。
圖 4.白背景,黑文本
通過與之相同的方法,您可以創建一個帶有白文本、黑背景、普通大小字體的高對比度的look and feel,您只需提供如清單4所示的另一個資源文件。
清單 4. HighContrastLAF.properties:黑背景,白文本
1. name = High Contrast Look And Feel
2. description = White on black
3. iconMagnificationFactor = 1
4. fontName = Dialog
5. fontSize = 14
6. backgroundColor = 000000
7. foregroundColor = FFFFFF
8. primaryColor1 = FFFFFF
9. primaryColor2 = 000000
10. primaryColor3 = 000000
11. secondaryColor1 = FFFFFF
12. secondaryColor2 = 808080
13. secondaryColor3 = 000000
14. selectionForeground = 000000
15. selectionBackground = FFFFFF
圖 5 顯示了清單4的結果。
圖 5. 黑背景,白文本
在您的Java應用程序中使用新的look and feel
通過在 main 方法中第一個窗口小部件創建之前調用下面一行代碼,您便可以在任何Swing應用程序中使用新創建的look and feel:
UIManager.setLookAndFeel("HighContrastLAF");
理想情況下, 您的產品應該能夠提供一個對話框或者偏好選擇頁面,以便用戶能夠選擇他們中意的look and feel。但是,如果您不想在這方面花那麼大的力氣,那麼一種更輕松的解決方案是使用系統屬性來允許用戶在啟動該程序的命令行中指定look and feel,如清單5所示。
清單 5. 從系統屬性初始化LAF
String plaf = System.getProperty("plafName") ;
if (plaf!=null) try {
UIManager.setLookAndFeel(plaf);
} catch (Exception e) { ("Error loading PLAF "+plaf+":"+e);}
當用戶啟動應用程序時,他們可以通過在命令行中使用以下語法來選擇一個特定的look and feel:
java -DplafName=HighContrastLAF -classpath
CLASSPATH MAINCLASS ARGUMENTS
結束語
在本文中,我們展示了定制跨平台的Metal look and feel是件多麼容易的事情。正如我們所討論的,這件事可以通過繼承 MetalLookAndFeel 和 DefaultMetalThemes 類來完成。我們還展示了如何輕松地通過使用矢量圖標來對圖標進行放大。您可以在您的項目中直接使用本文提供的源代碼,或者適當地作些修改,以便為弱視用戶提供更多的定制空間。
文章來源:
http://www.ibm.com/developerworks/cn/java/j-customlaf/