kermart

          k

           

          分層Pane結(jié)構(gòu)與Swing組件高級(jí)特性的實(shí)現(xiàn)

            這個(gè)題目起的有點(diǎn)難懂,但也實(shí)在想不出更好的題目來(lái)。所謂分層Pane結(jié)構(gòu)是指JFrame/JApplet/JDialog等Swing頂層容器的JRootPane/JLayeredPane/GlassPane/ContentPane結(jié)構(gòu)。所謂Swing組件高級(jí)特性其實(shí)是指某些組件的特殊功能的實(shí)現(xiàn),比如彈出菜單、Tooltip、JComboBox的下拉窗口、Drag and Drop實(shí)現(xiàn)、Docking Pallete窗口等等。這些特性同普通組件不同,它們往往需要?jiǎng)討B(tài)的變化、覆蓋其他組件,它們之間存在一定層次關(guān)系。那么Swing中是怎么樣實(shí)現(xiàn)這些功能呢?
            一直以來(lái)想寫(xiě)一篇文章來(lái)描述這個(gè)關(guān)鍵結(jié)構(gòu),但每次總被自己的語(yǔ)言表達(dá)能力所限制。Swing這個(gè)精巧結(jié)構(gòu)是我嘆服的原因之一。雖然一般的GUI系統(tǒng)設(shè)計(jì)原理我都知道,但是細(xì)節(jié)如此處精細(xì)卻不是一開(kāi)始就能清楚的。我在2000年以前曾經(jīng)寫(xiě)過(guò)大量基于AWT Canvas的自定義組件,當(dāng)時(shí)認(rèn)為Swing的自定義組件也不過(guò)如此,原理不過(guò)也是給我一個(gè)刷子,我給你畫(huà)出來(lái)。但是上述所說(shuō)的這些特性,卻從來(lái)沒(méi)能實(shí)現(xiàn)過(guò)。我想過(guò)很多方法,做過(guò)很多實(shí)驗(yàn),但終究沒(méi)有想透這一層。之后某次偶然機(jī)會(huì),看到了下面這張著名的圖,使我豁然開(kāi)朗。讓我又一次理解了創(chuàng)新需要跳出舊的思維模式勇氣和智慧。

            簡(jiǎn)單來(lái)說(shuō)Swing中這些頂層容器的多Pane結(jié)構(gòu)是實(shí)現(xiàn)這些特性的基礎(chǔ)。這些Pane實(shí)際是一些特殊的JComponent,它們之間存在包含被包含、覆蓋被覆蓋的樹(shù)狀多層次結(jié)構(gòu)。我重新畫(huà)了上面這張圖,使得其更具體、更直觀,更容易理解些:

          其實(shí)有了這張圖,加上圖形系統(tǒng)中Z-order的概念,就不難理解并實(shí)現(xiàn)上面提到的特性。Z-order概念和圖形學(xué)中Z深度是一致的。離觀察點(diǎn)近的物體總是會(huì)遮擋離觀察點(diǎn)遠(yuǎn)的物體。物體所在法平面離觀察點(diǎn)的距離就是所謂Z深度。Swing中通過(guò)先畫(huà)出Z-order遠(yuǎn)(小)的組件,再畫(huà)Z-order近(大)的組件的方法實(shí)現(xiàn)組件之間的遮擋關(guān)系。每個(gè)組件所在平面的都有一個(gè)數(shù)字描述其位置,這個(gè)位置同三維坐標(biāo)系中的Z軸類(lèi)似,離觀察者越近,坐標(biāo)越大:

            Swing的頂層容器都包含有一個(gè)JRootPane,該JRootPane是一切Swing組件起點(diǎn)。JRootPane中包含了一個(gè)JLayeredPane和一個(gè)GlassPane。GlassPane和JLayeredPane都是充滿(mǎn)JRootPane的。GlassPane缺省情況下是不可見(jiàn)的,因此我們看到都是JLayeredPane。GlassPane如果是可見(jiàn)的,它Z-order大于任何其他組件,因此它會(huì)覆蓋住整個(gè)窗口,使得所有的鼠標(biāo)事件都被它截獲。另外通常可見(jiàn)情況下它是透明的,因此你能仍然看到JLayeredPane上面的一切,但是JLayeredPane上面的組件都得不到鼠標(biāo)事件。
          GlassPane這個(gè)奇怪的組件主要是用來(lái)實(shí)現(xiàn)Drag & Drop以及跨組件渲染用的。NetBeans和Eclipse中哪種常見(jiàn)的Docking Frame的實(shí)現(xiàn)就和這種組件相關(guān)。這些工程、文件、源代碼的窗口其實(shí)不過(guò)是普通的Swing組件,它們本身并不能實(shí)現(xiàn)這種拖拽功能。鼠標(biāo)在它們上面標(biāo)題欄區(qū)域按下之后,標(biāo)題欄組件會(huì)檢測(cè)到這種事件,經(jīng)過(guò)粘連性判斷后,如果發(fā)現(xiàn)這些鼠標(biāo)事件目的是拖拽窗口,這種Docking系統(tǒng)就會(huì)將拖拽區(qū)域(即所謂的ClientArea)的GlassPane設(shè)置為可見(jiàn),于是下面的一些列拖拽鼠標(biāo)事件就被這個(gè)GlassPane所接管了過(guò)去。GlassPane是覆蓋于應(yīng)用程序ClientArea的透明組件,它處理這些事件時(shí)計(jì)算出當(dāng)前鼠標(biāo)位置所蘊(yùn)含著的拖拽動(dòng)作,并根據(jù)這些動(dòng)作畫(huà)出相應(yīng)的焦點(diǎn)矩形。NetBeans的Docking Framework一個(gè)拖拽過(guò)程如下圖所示.注意GlassPane是背景透明的,所以可以在上面畫(huà)背景透明的焦點(diǎn)矩形:

            JLayeredPane是實(shí)現(xiàn)彈出式窗口或類(lèi)似Pallete浮動(dòng)窗口的主要組件。如同它的名字一樣,它將自己的內(nèi)部結(jié)構(gòu)也分成許多亞層。在使用它的add(Component, Object)方法加入組件時(shí),第二個(gè)參數(shù)是一個(gè)Integer值,這個(gè)值決定了加入的層。這個(gè)值相當(dāng)于前面所說(shuō)的Z-order值。目前主要有下面幾個(gè)預(yù)定義值:
          public final static Integer DEFAULT_LAYER = new Integer(0);
          這層加入的缺省層。
            public final static Integer PALETTE_LAYER = new Integer(100);
          這層是定義Palette窗口的層。那種浮動(dòng)選項(xiàng)窗口屬于這一層。
            public final static Integer MODAL_LAYER = new Integer(200);
          這層是模態(tài)對(duì)話(huà)框的層。這個(gè)模態(tài)對(duì)話(huà)框應(yīng)該是指JInternalFrame的模態(tài)對(duì)話(huà)框,而不是JDialog。
            public final static Integer POPUP_LAYER = new Integer(300);
          這層是菜單、下拉框窗口、Tooltip等窗口浮動(dòng)的層。
            public final static Integer DRAG_LAYER = new Integer(400);
          這一層是拖拽層,組件可以在這一層被托拽。
            public final static Integer FRAME_CONTENT_LAYER = new Integer(-30000);
          這一層是ContentPane和MenuBar所在的層。注意它非常小,前面所有層的組件都會(huì)覆蓋這一層的組件。我們知道ContentPane是所有應(yīng)用程序組件所在的地方。
            JLayeredPane直接包含有ContentPane組件。應(yīng)用程序如果定了MenuBar,JLayeredPane還包含MenuBar。注意JLayeredPane本身沒(méi)有布局管理器,它對(duì)組件的布局是由它的父容器JRootPane的布局管理器RootLayout來(lái)完成的。簡(jiǎn)單來(lái)說(shuō),所在層數(shù)值小的組件有可能被高層組件所覆蓋。Swing將不同類(lèi)型的組件放置在不同層面上,就實(shí)現(xiàn)了文章一開(kāi)始提到的特性:菜單、浮動(dòng)窗口、下拉框窗口和Tooltip等。當(dāng)然這些窗口有可能不是JLayeredPane上的輕量級(jí)Swing組件,當(dāng)它們的邊界超過(guò)頂層容器的窗口時(shí),這些窗口的就變成了重量級(jí)AWT窗口。這在上一篇文章《如何混排Swing和AWT組件中已經(jīng)提到過(guò)。
            下面是這些Pane組件之間的樹(shù)狀包含關(guān)系圖:

            本文的目的是講述Swing的這種組件層次結(jié)構(gòu),并不是講述如何使用JLayeredPane和GlassPane來(lái)實(shí)現(xiàn)某中特殊的功能。如果需要學(xué)習(xí)如何使用它們實(shí)現(xiàn)某些特殊效果,Java Tutorial的Swing部分提供了詳盡的編程資料。Java Tutorial的Swing部分編程在:
            如何使用RootPane、GlassPane和JLayeredPane分別見(jiàn)下面的章節(jié):

          posted on 2012-07-26 11:21 kermart 閱讀(1246) 評(píng)論(0)  編輯  收藏


          只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿

          隨筆檔案

          收藏夾

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 来安县| 东乡族自治县| 清苑县| 云浮市| 墨江| 龙门县| 连山| 孟州市| 华池县| 鄄城县| 和平县| 花垣县| 麟游县| 定西市| 比如县| 图木舒克市| 静安区| 盘山县| 东海县| 盐城市| 甘德县| 屏山县| 长丰县| 娱乐| 雅江县| 信丰县| 中西区| 莱芜市| 佳木斯市| 甘谷县| 保靖县| 彰化市| 金坛市| 金沙县| 巴林右旗| 云梦县| 盐津县| 和政县| 凤山市| 宜丰县| 昌乐县|