AWT/Swing中的Repaint, paint, update

1.? ? Core java ch 14 confusion

讀Core java 卷I,14.1節(jié)的時候,有一段用于在UI上面移動小球的代碼,用了paint方法,而不是我們平時用的比較多的repaint,而且jdk文檔中明確注明了不推薦直接調(diào)用paint,所以有些困惑。


對此,書中的解釋是:But if you try to call?comp.repaint()in this program, you’ll find that the panel is only

repainted after the?addBall?method has returned.?

2.? ? Testing, repaint with paint

查了相關(guān)文檔,發(fā)現(xiàn)paint和repaint的區(qū)別還是很大的。Paint方法一般在UI事件的callback中被調(diào)用,以進(jìn)行組件的繪制。如果直接調(diào)用paint,繪制將發(fā)生在AWT/Swing的事件機(jī)制之外。而repaint會向AWT注冊一個異步請求,告訴AWT哪個組件需要繪制。這個請求將觸發(fā)組件的update方法。如果對于同一個組件,在第一個repaint被處理之前,有多個repaint被調(diào)用,那么這多個請求將合并為一個請求。

在實例代碼中,addBall方法是在事件callback函數(shù)(event->addBall())中調(diào)用的,在按鈕按下觸發(fā)的callback函數(shù)開始之后,addBall才會執(zhí)行。如果這里用repaint,那么在callback函數(shù)(event->addBall())執(zhí)行結(jié)束之后,所有的由repaint注冊的update(其實就是paint)方法才會執(zhí)行,根據(jù)前面的規(guī)則,所有的repaint請求被合并了。因此,如果用repaint,將會看到球直接移動到了最終位置。

把方法改成repaint,在repaint方法和paint方法中打出log,


看到輸出結(jié)果:

==============? repaint

==============? repaint

==============? repaint

================== paint


3.? ? AWT/Swing的歷史

Java1.0 剛出現(xiàn)的時候,包含了一個用于基本的UI設(shè)計的包,名叫AWT (Abstract Window Toolkit)。AWT將繪制UI的任務(wù)委托給了目標(biāo)平臺自帶的GUI繪制工具箱。但是AWT不能很好的處理平臺之間的差異。

1996年Netscape創(chuàng)建了IFC(Internet Foundation Class),采取了與AWT完全不同的工作方式。在這種工作方式下,目標(biāo)平臺的GUI繪制工具箱負(fù)責(zé)創(chuàng)建和繪制窗口,而像按鈕、菜單這樣的用戶界面元素由IFC繪制到窗口上。

之后,Sun和Netscape合作,完善了IFC,創(chuàng)建了Swing。Swing作為java1.1的擴(kuò)展部分使用,并最終在java1.2成為了標(biāo)準(zhǔn)庫的一部分。

從Swing的實現(xiàn)方式來說,Swing沒有完全替代AWT,而是基于AWT架構(gòu)之上。Swing提供了能力更為強(qiáng)大的用戶界面組件,而且需要使用AWT的事件處理機(jī)制。也就是說,不管是AWT還是Swing,UI的繪制都依賴于callback機(jī)制:

a.? ? 監(jiān)聽器對象是一個實現(xiàn)了特定監(jiān)聽器接口的類的實例。

b.? ? 事件源(例如按鈕)是一個能夠注冊監(jiān)聽器對象并發(fā)送事件的對象。

c.? ? 當(dāng)事件(例如點(diǎn)擊按鈕)發(fā)生時,事件源將事件對象傳遞給所有注冊的監(jiān)聽器。

d.? ? 監(jiān)聽器對象將對事件作出響應(yīng)(執(zhí)行callback函數(shù))

AWT和Swing依賴于組件的paint方法繪制UI。這里需要注意的是,一般情況下,應(yīng)該避免在callback之外繪制UI,因為這樣做跳出了AWT/Swing的事件機(jī)制,很容易引起UI繪制中的混亂。因此不推薦直接調(diào)用paint。

4.? ? Lightweight vs heavyweight

從應(yīng)用開發(fā)者的角度來說,二者基本上沒有區(qū)別:他們都是調(diào)用API paint對組件進(jìn)行繪制。然而,lightweight完全是用java code 開發(fā)的,所以在實現(xiàn)機(jī)制上還是有細(xì)微的差別。因為Lightweight組件必須繪制在heavyweight組件上,當(dāng)heavyweight組件被告知需要調(diào)用paint的時候,它應(yīng)該將繪制信息傳遞給其所有的子lightweight組件。而且,lightweight具有透明性,著意味著update不會清空lightweight的背景(這一點(diǎn)有別于heavyweight組件)。關(guān)于update方法的詳細(xì)信息將在稍后闡述。

a)? ? ? Lightweight: 重用 heavyweight組件。

b)? ? ? Heavyweight: opaque, native windows.

5.? ? System trigger vs application trigger

系統(tǒng)觸發(fā)的事件和應(yīng)用觸發(fā)的時間最終要調(diào)用組件的paint方法,所以說二者沒有本質(zhì)區(qū)別。

a)? ? ? System trigger:新建組件,resize,從“破損”的狀態(tài)下“修復(fù)”(沒有顯示不完全à顯示完全)。

?i.? ? ? ? ? ?Things with AWT

????1.? ? ? ?AWT決定需要繪制的部分

? ? 2.? ? ? ?AWT導(dǎo)致事件分發(fā)線程觸法組件的paint方法

b)? ? ? App triggered: 由用戶動作觸發(fā)的事件,導(dǎo)致UI的變化。在這種情況下,可以通過調(diào)用組件的repaint方法繪制組件。如果組件較為簡單,可以調(diào)用repaint的無參數(shù)版本,以繪制整個組件;反之,如果組件較為復(fù)雜,則可以調(diào)用repaint的有參數(shù)版本,從而僅僅繪制需要的部分。為了響應(yīng)狀態(tài)的變化(MVC模型),程序決定繪制組件的部分還是全部。

?i.? ? ? ? ? ?Things in AWT

????1.? ? ? 程序調(diào)用組件的repaint方法,該方法向AWT注冊一個異步請求,告訴AWT哪個組件需要繪制。這個請求將觸發(fā)組件的update方法。如果對于同一個組件,在第一個repaint被處理之前,有多個repaint被調(diào)用,那么這多個請求將合并為一個請求。

? ? 2.? ? ? ?對于heavyweight組件,默認(rèn)情況下,Update清空組件需要更新的部分,然后調(diào)用組件的paint方法,Update方法支持所謂的“增量繪制”。而對于lightweight組件,Update直接調(diào)用paint。因此對于lightweight組件來說,update和paint沒有區(qū)別。

6.? ? AWT vs Swing

從Swing的實現(xiàn)方式來說,Swing沒有完全替代AWT,而是基于AWT架構(gòu)之上,并對AWT進(jìn)行了增強(qiáng)。增強(qiáng)的特性包括:

a.? ? Double Buffer Support: 這是Swing區(qū)別于AWT的最顯著特性,該特性為每一個container hierarchy提供了唯一個offscreen(幕后,區(qū)別于onscreen) Double Buffer。如果這個特性被enabled(默認(rèn)情況下enable),那么graphics對象將被轉(zhuǎn)成offscreen graphics,接下來,繪制過程在double buffer中進(jìn)行,繪制結(jié)束后,offscreen graphics會被原始的graphics對象拷貝回組件。

b.? ?Additional Paint Properties:Swing增加了一些屬性,以提高內(nèi)部繪制算法的效率。這些屬性用于描述兩類問題:

????a)? ? ? 透明性,在繪制lightweight組件的時候,可能不會繪制出組件的所有像素,所以必須從container hierarchy向上追溯到第一個heavyweight組件,最后進(jìn)行“back-to-front”的繪制操作。

????????i.? ? ? ? ? ?opacity:如果為true,組件同意繪制自己的全部像素。對于大多數(shù)組件,opacity為true。

? ? ?b)? ? ? 重疊組件:lightweight組件之間可能相互重疊。

? ? ? ? i.???????????[endif]IsOptimizedDrawingEnabled:如果為true,表示沒有任何直接子組件是重疊的。通過檢查這個屬性,Swing repaint可以很容易的查找組件之間的重疊關(guān)系。

c.? ? UI Delegate: 絕大多數(shù)Swing組件的繪制被代理給UI Delegate(separated Look-and-feel 對象)

d.? ? RepaintManager:用于最大化Swing組件的繪制效率。

e.? ? Swing的繪制機(jī)制和AWT類似,但是paint方法的實現(xiàn)是不一樣的。

? ?a)? ? ? Paint依次調(diào)用三個方法,paintComponet-->paintBorder -->paintChild

? ?b)? ? ? 如果繪制請求來自于頂層heavyweight對象(JFrame,JDialog,JWindow,JApplet),事件分發(fā)線程調(diào)用該heavyweight對象的paint方法:

? ? ? ? ? ? i.? ? ? ? ? ?如果double Butter 特性被enabled,將graphics對象轉(zhuǎn)為offscreen graphics對象。

? ? ? ? ? ? ii.? ? ? ? ? 調(diào)用paintCompnent

? ? ? ? ? ? iii.? ? ? ? ? 調(diào)用paintBorder

? ? ? ? ? ? iv.? ? ? ? ? ?調(diào)用paintChildren (傳入屬性值,opacity,isOptimizedDrawingEnabled)

? ? ? ? ? ? v.? ? ? ? ? ?如果double Butter 特性被enabled,將offcreen graphics轉(zhuǎn)為原始的graphics對象

? ? ?c)? ? ? ?如果繪制請求來自來自于對repaint的調(diào)用

? ? ? ? ? ? ? i.? ? ? ? ? ?repaint在組件的RepainManager 上注冊一個repaint請求,repaintManger用invokeLater將一個runnable(用于稍后處理請求)放入事件分發(fā)線程。

? ? ? ? ? ? ? ii.? ? ? ? ? ?當(dāng)runnable運(yùn)行的時候,會使得repaintManager調(diào)用組件的paintImmediately 方法。PaintImmediately方法類似updtate方法。在Swing中,永遠(yuǎn)不會調(diào)用update方法。

? ? ? ? ? ? ? ?iii.? ? ? ? ? ?利用clip、opacity和isOptimizedDrawingEnabled信息,決定從哪個根組件開始繪制。

? ? ? ? ? ? ? ?iv.? ? ? ? ? ?轉(zhuǎn)到b)

Reference

https://docs.oracle.com/javase/7/docs/api/java/awt/Component.html

https://www.oracle.com/technetwork/java/painting-140037.html#triggers

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 參考文獻(xiàn):《Java瘋狂講義》(第三版) 絕對定位 絕對定位步驟: 1、Container的布局管理器設(shè)成null...
    houc閱讀 389評論 0 0
  • 一、通用篇1.1 不用new關(guān)鍵詞創(chuàng)建類的實例1.2 使用非阻塞I/O1.3 慎用異常1.4 不要重復(fù)初始化變量1...
    rebooted閱讀 367評論 0 1
  • 個人筆記,方便自己查閱使用 Contents Java LangAssignment, ReferenceData...
    freenik閱讀 1,529評論 0 6
  • 待更新 概述 在Java初期,包含了一個用于基本GUI程序設(shè)計的類庫,稱為AWT (Abstract Window...
    染微言閱讀 1,139評論 0 4
  • https://segmentfault.com/a/1190000000732617http://yanhaij...
    butterflyq閱讀 247評論 0 0

友情鏈接更多精彩內(nèi)容