Swing組件的paint方法的處理流程
昨晚回去后還是覺得Component對象本身說的太簡單,想來想去,覺得內(nèi)容實在是太多,有必要補充兩個續(xù)文說明Component的其它概念。今天介紹Swing組件paint方法的處理流程,這個流程能使我們理解許多Swing機制。
Swing組件的paint方法是內(nèi)部接口方法,一般用戶不要直接調(diào)用這個方法,它總是在事件調(diào)度線程中調(diào)用。一般說來除了系統(tǒng)刷新事件觸發(fā)這個方法, Component的repaint也觸發(fā)這個方法的調(diào)用。repaint方法常用于當組件狀態(tài)發(fā)生變化時刷新界面使用。repaint方法是Swing 中少數(shù)幾個線程安全的方法,可以在任何線程中調(diào)用它。它的原理是往事件隊列中post一個PAINT事件。由于事件隊列的事件是被事件調(diào)度線程同步執(zhí)行的,所以這個方法總是線程安全的。事件調(diào)度線程從PAINT事件中獲取事件源組件,從系統(tǒng)申請到圖形設(shè)備資源后,調(diào)用該組件的update方法。 update是AWT時代遺留下來的產(chǎn)物,本意是AWT組件畫好組件背景后,再調(diào)用paint方法畫出組件的前景。Swing出現(xiàn)后這個方法就被棄用了,所有邏輯都轉(zhuǎn)到paint方法里。Update只是簡單地調(diào)用paint方法來完成組件的渲染。老的Java教材上經(jīng)常可以看到,所謂repaint調(diào)度 update方法,update接著調(diào)用paint方法,自定義組件需要重載paint方法等話語,就是因為這個歷史造成的。
現(xiàn)在JComponent的實現(xiàn)已經(jīng)把paint方法改造成可以嵌套多重機制地方,這些機制包括層次渲染、邊框、透明背景、雙緩沖以及皮膚等。這些機制分別實現(xiàn)不同目的的組件提供了方便。
圖形用戶界面的組件按照其在組件樹上的角色可以分為容器組件和葉組件。Swing模型把葉組件當作是特殊、沒有子組件的容器組件,只是JComponent繼承Container類,所有Swing組件繼承JComponent的原因。
JComponent在paint方法中首先根據(jù)組件是否需要使用雙緩沖,封裝好圖形設(shè)備對象,然后經(jīng)過一番處理后調(diào)用paintComponent方法畫出自身,然后調(diào)用paintBorder畫出邊框,最后調(diào)用paintChildren來完成子組件的渲染。
paintComponent意思是畫出組件自身,不包括子組件。因此前一文章中的MyButton可以通過覆蓋paintComponent方法來完成 MyButton的重畫。在JComponent實現(xiàn)中,JDK 6的paintComponent的代碼為:
- protectedvoidpaintComponent(Graphicsg){
- if(ui!=null){
- GraphicsscratchGraphics=(g==null)?null:g.create();
- try{
- ui.update(scratchGraphics,this);
- }
- finally{
- scratchGraphics.dispose();
- }
- }
- }
可以看出,背景透明機制在這兒實現(xiàn)。首先UI Delegate對象判斷Component是否背景透明的,如果不是透明的,則使用背景色填充整個Component區(qū)域,然后調(diào)用paint(g, c)來完成組件在這種LookAndFeel種的渲染。了解了這些后,我們幾乎就明白了Swing如何實現(xiàn)背景透明和如何切換皮膚。由于后面的文章還會對 UI Delegate和皮膚機制詳細描述,這兒就到此為止。
目前還不要求實現(xiàn)皮膚,在這種情況下只需要重載paintComponent方法就行了,如果需要背景透明機制,可以模仿上面代碼,MyButton的paintComponent可以這樣寫:
- publicvoidpaintComponent(Graphicsg){
- if(isOpaque()){
- g.setColor(getBackground());
- g.fillRect(0,0,getWidth(),getHeight());
- }
- if(pressed){//按鈕按下去了
- //畫出按下的樣子
- }else{
- //畫出抬起的樣子
- }
- }
paintChildren完成容器類組件的子組件的渲染。JDK缺省的實現(xiàn)是調(diào)用各個自組件的paint方法。一般來說不需要重載這個方法。如果想改變諸如組件Z-order遮擋順序,可以覆蓋這個方法,從相反順序調(diào)用組件的paint方法。
到這兒我們對Swing的結(jié)構(gòu)有了更深化的理解,UI Delegate機制也已經(jīng)初露倪端。還有幾個重要Swing Component概念或者機制沒有講,明天的續(xù)文再對它們做出說明。
【編輯推薦】