Swing第二刀:枝間新綠一重重
關于綠色
喜歡綠色,喜歡雅黑,無可救藥。在這個吵吵鬧鬧的軟件行業,綠色也忽然從“春風一拂千山綠”唯美變成俗不可耐的buzzword。比如:
綠色軟件:大大的buzzword。忽然一夜之間,所有的軟件都綠色了,好像不“綠”就跟不上形勢。比如綠色殺毒,綠色OFFICE,綠色ERP,綠色windows。反正全綠。
綠色征途:看,精神鴉~片也可以很“綠”的;
綠~壩-花季護航:呃,老好的軟件,不多說了;
綠色世博:嗯,喊的老響了。至今一頭霧水。


框架,還是框架
這個程序的設計初衷是快速建立一個美觀的Swing應用程序外觀。但是,具體來說,它又并非完全是下面幾個東西:
LookAndFeel:這個程序并非一個LnF。一個LnF會對所有的Swing組件進行重新定義Paint并可以通過UIManager.setLookAndFeel進行啟用。這個程序用到了大量LookAndFeel的機制,甚至也直接定義了不少UI。不過它并不是一個完整的LookAndFeel。這些定制完全是為這個程序框架服務的。也就是說,這些UI和重繪機制只有在當前的程序框架起作用,而無法指望一句UIManager.setLookAndFeel就將你的任意Swing程序變成上圖風格。
組件庫:也不是組件庫。其實里面的組件,除了這個OutlookPane(左側的模塊樹)是完全新做出來的(而且沒有從JTabbedPane繼承,也許理論上還經不起太嚴謹的推敲),其他的組件都是很簡單、現成的。例如列表、按鈕、菜單等,都是直接用Swing的,只是重載了一些方法或者定義了UI而已。而且我并非是想讓大家直接new OutlookPane()這樣來使用,而是使用XML文件對整個界面進行配置使用;
GUI程序框架:似乎有點大。這僅僅是一個很小的程序而已。
做Java的喜歡滿嘴Framework。你要是不能氣定神閑一口氣提到20個Framework并有意無意的暗示自己很精通,那~都不好意思跟人家說話;最好再能挑一個有點名氣的,指手畫腳、評頭論足、怒其不爭一下下,那就像大牛了(例如Hibernate就是個很不錯的candidate)。所以,咱這個小程序也就死乞白賴往“框架”上湊湊,反正已經帶上了“綠帽子”,也不怕丟人丟到底。
好吧,這是一個框架,雖然我也不知道框架該怎么定義。反正我的設計初衷是:如果你用Swing開發一個類似上圖結構的應用程序,那么你可以直接用這個框架。這個程序框,包含了上面菜單、地下狀態條、左邊模塊欄、右邊功能快捷列表,中間多tab標簽頁的各種內容(也提供了幾個常用的內容頁風格,例如列表、流程圖等)。這個窗口已經被封裝好,通過XML配置文件來定義菜單、狀態條、模塊欄、流程圖、右邊的快捷列表。同時,這些都是聯動的。例如:點擊左邊的模塊欄中的子模塊,一個對應的流程圖會顯示在中間tab頁;選中流程圖中的節點,可以把該節點相關的功能列在右側。點擊右側列表,可以執行各種定義好的動作(動作通過動作碼定義,后面會詳細介紹)。使用么,直接new 一個窗口類,set各個部分的XML文件名,然后setVisible(true)就OK了。至于中間的各個組件和大家關心的LookAndFeel,則都定義好了,基本上不用太關心細節。
不管怎么說,我們就叫它“框架”吧。
XML配置
每個應用程序都千奇百怪,功能各異。如何用一個同樣的界面來組織呢?的確,這個界面并非適合所有人。不過這里的所有菜單、按鈕、流程圖、圖標等,其動作都是可以用一個“動作碼”類定義的,所有的動作都會回調一個統一的函數。而我們只要在這個函數處插入監聽,就可以攔截具體動作碼,執行我們想做的任何事情,例如格式化C盤、往aobama@whitehouse.com郵箱發個垃圾郵件啥的。
例如,要定義主菜單,通過這個XML:

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

以上XML可以定義一個System的主菜單,以及一個One Sub Module的菜單項,以及一系列的二級菜單。每個菜單都可以設置icon圖標、文字、tooltip文字,以及動作碼(就是那個action)。如下圖:

左側的模塊欄就是典型的Outlook的風格,很多軟件干脆都叫它OutlookPane(我這里也是如此)。這個OutlookPane的配置,通過如下類似XML:














同樣,主模塊(也就是每個大分欄)包含了模塊欄的文字、icon圖標(選中和未選中兩個),以及一個xml文件。這個xml文件包含了一個流程圖,流程圖包含了具體的子模塊。點擊展開大模塊欄后,所有的子模塊也會顯示在欄目中,同時模塊的流程關系會通過對應的xml文件中定義的方式,顯示在一個圖形化的流程圖界面中,最終顯示在中間的tab頁上。

可以看到,左側的模塊列表和中間的圖形節點是一一對應的。當鼠標選中節點后(變成橙色),左側的列表對應的項也會被選中。同時,和這個節點(代表了一個具體子模塊)相關的功能,都會顯示在右側的快捷列表中(這是通過指向的network.xml文件定義的)
上面例子中的Network.xml內容舉例如下:

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

其中,每個node定義了一個子模塊節點。節點上包含x、y坐標信息、文本信息、tooltip、icon圖標(中間大的主圖標),以及三個按鈕。每個node如圖所示,可以攜帶3個按鈕。每個按鈕可以掛一個圖標、tooltip、icon以及動作碼。我們可以定義其任意動作。

然后,每個node又攜帶了一個shortcuts列表,包含了這個節點所有相關的功能點,在node被選中后,以右側的列表方式列出。如圖所示:

此外,流程圖中的箭頭是通過類似如下XML在network.xml中定義:

其中x、y是坐標,direction是方向,可以是上下左右以及斜向共8個方向。此外rotation還提供了旋轉角度。如果right_up這個45度的右上角度不符合要求,可以在增加rotation進行進一步調節。
右側快捷列表的分割文字,也是通過如下xml進行定義:











分隔條可以攜帶一個文字,用來對很多列表項進行分組:

還有工具條也是可以配置的。工具條在這個框架里被放在了模塊欄的頂部。通過如下XML配置其按鈕:

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

其中<separator>定義了一個分割豎線 ,完全美觀之用。顯示效果如下:

最后一個配置項是軟件右上角的LOGO。每個系統都想有一個地方漂亮的顯示咱家的LOGO,那才有成就感!這里通過menubar菜單的XML文件如下配置:

可以對圖片、tooltip進行定義。顯示效果如下:

這樣,一個完整的”純綠色“應用程序框架就差不多被”配置“出來了。
程序接口
其實設計初衷是無需使用源代碼,直接使用下方提供的jar包即可進行二次開發。因為畢竟通過XML就可以對界面元素進行定義了。如果要把這個框架集成到你的應用程序中,并執行你的具體動作,只需要對free.Shell這個類進行一個函數重載即可。










在Shell這個類中,界面上所有的按鈕、菜單、列表等被點擊后,都會回調這個Shell的command方法,并傳回action字符串,也就是我們在XML中定義的動作碼。接著你就用if else或者case啥的進行處理動作吧!當然也可以調用addTab方法在Shell界面中添加一個tab頁面。其使用方法會下次詳細闡述。
關于效率、內存、布局和其他
有朋友說很擔心執行效率、內存占用。這是對Swing常被攻擊的的一個老話題了。簡單直接的回答是:Swing效率沒問題。內存占用沒問題。滿眼嘩嘩一片字符串,就一定占內存嗎?table有1000行,渲染的花里胡哨,就內存問題嗎?完全不是這么一回事。例如,如果你了解Swing的table的renderer機制,其實無論表格有多少行,一個列是用同一個renderer實例來paint的。注意,是一個實例哈。editor也是一樣。很多初學者以為這一列用JComboBox編輯,1000行就會create成1000個ComboBox。那就完全錯了。Renderer就是一個“橡皮章”,一個章,不停的在每個格子里面“蓋章”,重繪就重新蓋;Editor就是當一個“蘿卜”,哪個“坑”需要編輯時,table動態把它“放”在這個單元格(坑)上面,下次下個單元格需要編輯,再被挪過去。對于一個列來說,就一個蘿卜,一個橡皮章。怎么會說“占用內存”?如果說1000行字符串占用內存,那這些字符串用什么語言和平臺不占用內存呢?同樣字符串在不同的語言和平臺上可以說占用內存幾乎沒什么差別。這個以后可以專門討論。
在這個本程序中,狀態欄上有一個封裝好的內存監控工具條:
它的作用是監測目前Java的總的申請的堆內存以及使用的內存。相關代碼如下:








上面圖片中的“18M/63M”標明默認Java堆大小是64M目前使用了18M。嘗試多打開一些表格界面、拓撲圖界面,可見內存使用并不是很多。
說Swing的效率低,也不是很有說服力。其實Swing本質還是Java2D在paint東西,看看那些雜亂的Metal***UI源碼就知道了。不過Swing確實設計的夠復雜啰嗦,一個LnF就能繞死人。這些機制會導致Swing慢一些。不過說到底程序的快慢瓶頸還不是在Swing上,還是在如何設計和使用上。例如線程的處理等等,這些都不是初學者很容易搞定的東西。這也導致Swing總是被貼上“慢”的標簽。
自動布局方面,也是比較啰嗦的。如果用IDE的話,推薦NetBeans里面的GUI編輯工具,它使用的實際是Matisse這個layout。這里有兩篇官方文章介紹:
http://wiki.netbeans.org/UsingGUIEditor
http://netbeans.org/features/java/swing.html
如果手寫代碼,我還是推薦一個超強但比較復雜的TableLayout。這里有其介紹:
http://java.sun.com/products/jfc/tsc/articles/tablelayout/
其他簡單的布局,大多可以用Swing內置的幾個layout搞定。另外盡量多套用Panel進行嵌套,化繁為簡。不要試圖一次一個Panel+Layout把一個復雜的界面搞定,那樣會很累。
有朋友很不齒這里使用到了JGoodies和TWaver,這里也說明一下。在JGoodies的基礎上再去定制UI確實美觀了不少,不過理論上確實可以徹底拋開JGoodies。這樣就要完全徹底重寫一整套的LnF了,包括文本框按鈕啊所有的東西。目前確實還沒有這樣的時間和精力,以后會考慮出一個WithoutJGoodies版本。使用TWaver主要是為了做中間的流程圖和拓撲圖,并且使用的也比較順手了。如果不需要中間的拓撲圖流程圖,也可以without TWaver,以后會考慮改一版。不過這些東西都是很不錯的工具,能用就拿來為我所用,不喜歡用就借鑒一下了事。
程序下載
麻煩請至我之前發表文章的TWaver中文社區下載。
執行方法:解壓zip文件,雙擊其中的run.bat。
運行環境:Java 6。
其他說明:zip包中的free.jar就是本文提到的框架。其他兩個jar包是jgoodies lnf和twaver做流程圖的支撐包,可不用理會。
下一次我會詳細介紹每一個組件的制作方法和相關代碼。