溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

AWT和Swing繪畫(huà)的示例分析

發(fā)布時(shí)間:2021-12-27 15:21:19 來(lái)源:億速云 閱讀:136 作者:小新 欄目:編程語(yǔ)言

小編給大家分享一下AWT和Swing繪畫(huà)的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

AWT和Swing繪畫(huà)
在AWT中,對(duì)于重量級(jí)組件,在繪制時(shí)按照如下的調(diào)用進(jìn)行:

1)因?yàn)橄到y(tǒng)觸發(fā)而重繪:(說(shuō)白了,就是指這種重繪不是人為的,不是我們自己寫(xiě)代碼調(diào)用repaint()等函數(shù)進(jìn)行重繪,而是系統(tǒng)覺(jué)得有必要進(jìn)行重繪而進(jìn)行的。)
◆《AWT》確定是一部分還是整個(gè)部件需要繪畫(huà)。
◆《AWT》促使事件分派線程調(diào)用部件的paint()方法。

2)因?yàn)槌绦蛴|發(fā)而重繪:(人為在消息響應(yīng)函數(shù)中或其他地方強(qiáng)制進(jìn)行重繪的操作)
◆《程序》確定是一部分還是全部部件需要重畫(huà)以對(duì)應(yīng)內(nèi)部狀態(tài)的改變。
◆《程序》調(diào)用部件的repaint(),該方法向《AWT》登記了一個(gè)異步的請(qǐng)求 -- 當(dāng)前部件需要重畫(huà)。
◆《AWT》促使事件分派線程去調(diào)用部件的update() 方法。
◆如果部件沒(méi)有覆蓋(override)update()方法,update()的默認(rèn)實(shí)現(xiàn)會(huì)清除部件背景(如果部件不是“輕量級(jí)”),然后只是簡(jiǎn)單地調(diào)用paint()方法。

說(shuō)明:不論是那種觸發(fā)重繪的方式,均可以歸結(jié)到paint()函數(shù)上來(lái),那為什么對(duì)于程序觸發(fā)方式還要有個(gè)中間步驟“update()”呢?這是為了讓我們能夠通過(guò)重寫(xiě)update()方法后,在里面進(jìn)行我們想要的控制,也就是我們可以在這里做點(diǎn)文章。當(dāng)然我們也可以覆蓋paint()函數(shù),但是有了 update()函數(shù)之后,我們就可以不干擾paint(),讓其“全身心”的負(fù)責(zé)繪制,而在update()這個(gè)地方進(jìn)行我們需要的控制。比如提到的只能用到重量級(jí)組件的“增量繪制”,就是首先由系統(tǒng)觸發(fā)paint繪制,然后在這個(gè)基礎(chǔ)上(也就是背景下),在鼠標(biāo)左鍵的消息響應(yīng)函數(shù)中調(diào)用 repaint,然后重寫(xiě)update函數(shù),只是讓update函數(shù)畫(huà)新添加的內(nèi)容,而不在update函數(shù)內(nèi)部再調(diào)用paint函數(shù)了,這樣就避開(kāi)了 paint函數(shù),也就是實(shí)現(xiàn)了所謂的“增量繪制”。不過(guò)需要說(shuō)明的是,增量繪制只在一些特殊的GUI部件上好用,比如我們下面給的這個(gè)例子(就是剛用來(lái)描述“增量繪制”的那個(gè)例子)中就是用的Canvas類,該類直接繼承于Component類,注意不是繼承自Container類,因?yàn)樵?Container類中又實(shí)現(xiàn)了自己的paint方法,有了新的機(jī)制,這就和我們上述講的這一大套基于Component類的paint方法不一致了。

對(duì)于輕量級(jí)組件,都是繼承于Container類的,“輕量級(jí)”部件需要一個(gè)處在容器體系上的“重量級(jí)”部件提供進(jìn)行繪畫(huà)的場(chǎng)所。當(dāng)這個(gè)“重量級(jí)” 的“祖宗”被告知要繪制自身的窗體時(shí),它必須把這個(gè)繪畫(huà)的請(qǐng)求轉(zhuǎn)化為對(duì)其所有子孫的繪畫(huà)請(qǐng)求。這是由java.awt.Container的 paint()方法處理的,該方法調(diào)用包容于其內(nèi)的所有可見(jiàn)的、并且與繪畫(huà)區(qū)相交的輕量級(jí)部件的paint()方法。因此對(duì)于所有覆蓋了paint()方法的Container子類(“輕量級(jí)”或“重量級(jí)”,Container的子類不一定都是輕量級(jí)組件哦,呵呵)都需要在函數(shù)的最后調(diào)用父類的paint 方法,即super.paint(g)。

最后,對(duì)于AWT繪制,給出以下準(zhǔn)則:
◆對(duì)于大多數(shù)程序,所有的客戶區(qū)繪畫(huà)代碼應(yīng)該被放置在部件的paint()方法中。
◆通過(guò)調(diào)用repaint()方法,程序可以觸發(fā)一個(gè)將來(lái)執(zhí)行的paint()調(diào)用,不能直接調(diào)用paint()方法。
◆對(duì)于界面復(fù)雜的部件,應(yīng)該觸發(fā)帶參數(shù)的repaint()方法,使用參數(shù)定義實(shí)際需要更新的區(qū)域;而不帶參數(shù)調(diào)用會(huì)導(dǎo)致整個(gè)部件被重畫(huà)。
◆因?yàn)閷?duì)repaint()的調(diào)用會(huì)首先導(dǎo)致update()的調(diào)用,默認(rèn)地會(huì)促成paint()的調(diào)用,所以重量級(jí)部件應(yīng)該覆蓋update()方法以實(shí)現(xiàn)增量繪制,如果需要的話(輕量級(jí)部件不支持增量繪制) 。
◆覆蓋了paint()方法的java.awt.Container子類應(yīng)當(dāng)在paint()方法中調(diào)用super.paint()以保證子部件能被繪制。
◆界面復(fù)雜的部件應(yīng)該靈活地使用裁剪區(qū)來(lái)把繪畫(huà)范圍縮小到只包括與裁剪區(qū)相交的范圍。

Swing繪畫(huà)的處理過(guò)程
Swing處理"repaint"請(qǐng)求的方式與AWT有稍微地不同,雖然對(duì)于應(yīng)用開(kāi)發(fā)人員來(lái)講其本質(zhì)是相同的 -- 同樣是觸發(fā)paint()。Swing這么做是為了支持它的RepaintManager API (后面介紹),就象改善繪畫(huà)性能一樣。在Swing里的繪畫(huà)可以走兩條路,如下所述:

(A) 繪畫(huà)需求首先產(chǎn)生于一個(gè)重量級(jí)祖先(通常是JFrame、JDialog、JWindow或者JApplet):
1。事件分派線程調(diào)用其祖先的paint()
2。Container.paint()的默認(rèn)實(shí)現(xiàn)會(huì)遞歸地調(diào)用任何輕量級(jí)子孫的paint()方法。
3。當(dāng)?shù)竭_(dá)第一個(gè)Swing部件時(shí),JComponent.paint()的默認(rèn)執(zhí)行做下面的步驟:
◆如果部件的雙緩沖屬性為true并且部件的RepaintManager上的雙緩沖已經(jīng)激活,將把Graphics對(duì)象轉(zhuǎn)換為一個(gè)合適的屏外Graphics。
◆調(diào)用paintComponent()(如果使用雙緩沖就把屏外Graphics傳遞進(jìn)去)。
◆調(diào)用paintBorder()(如果使用雙緩沖就把屏外Graphics傳遞進(jìn)去)。
◆調(diào)用paintChildren()(如果使用雙緩沖就把屏外Graphics傳遞進(jìn)去),該方法使用裁剪并且遮光和optimizedDrawingEnabled等屬性來(lái)嚴(yán)密地判定要遞歸地調(diào)用哪些子孫的paint()。
◆如果部件的雙緩沖屬性為true并且在部件的RepaintManager上的雙緩沖已經(jīng)激活,使用最初的屏幕Graphics對(duì)象把屏外映像拷貝到部件上。

注意:JComponent.paint()步驟#1和#5在對(duì)paint()的遞歸調(diào)用中被忽略了(這里的JComponent指的是在paintChildren()函數(shù)中判斷出的需要遞歸調(diào)用的組件,在步驟#4中介紹了),因?yàn)樗性趕wing窗體層次中的輕量級(jí)部件將共享同一個(gè)用于雙緩沖的屏外映像。

(B) 繪畫(huà)需求從一個(gè)javax.swing.JCponent擴(kuò)展類的repaint()調(diào)用上產(chǎn)生:
1。JComponent.repaint()注冊(cè)一個(gè)針對(duì)部件的RepaintManager的異步的重畫(huà)需求,該操作使用invokeLater()把一個(gè)Runnable加入事件隊(duì)列以便稍后執(zhí)行在事件分派線程上的需求。

2。該Runnable在事件分派線程上執(zhí)行并且導(dǎo)致部件的RepaintManager調(diào)用該部件上paintImmediately(),該方法執(zhí)行下列步驟:

◆使用裁剪框以及遮光和optimizedDrawingEnabled屬性確定“根”部件,繪畫(huà)一定從這個(gè)部件開(kāi)始(處理透明以及潛在的重迭部件)。
◆如果根部件的雙緩沖屬性為true,并且根部件的RepaintManager上的雙緩沖已激活,將轉(zhuǎn)換Graphics對(duì)象到適當(dāng)?shù)钠镣釭raphics。
◆調(diào)用根部件(該部件執(zhí)行上述(A)中的JComponent.paint()步驟#2-4)上的paint(),導(dǎo)致根部件之下的、與裁剪框相交的所有部件被繪制。
◆如果根部件的doubleBuffered屬性為true并且根部件的RepaintManager上的雙緩沖已經(jīng)激活,使用原始的Graphics把屏外映像拷貝到部件。

注意:如果在重畫(huà)沒(méi)有完成之前,又有發(fā)生多起對(duì)部件或者任何一個(gè)其祖先的repaint()調(diào)用,所有這些調(diào)用會(huì)被折迭到一個(gè)單一的調(diào)用,即回到最上層(這里的層指的是那種Hierarchy,而不是展現(xiàn)給我們的最上面的那個(gè)圖或者按鈕)的SWing部件的paintImmediately(),調(diào)用它的repaint()。例如,如果一個(gè)JTabbedPane包含了一個(gè)JTable并且在其包容層次中的現(xiàn)有的重畫(huà)需求完成之前兩次發(fā)布對(duì)repaint()的調(diào)用,其結(jié)果將變成對(duì)該JTabbedPane部件的paintImmediately()方法的單一調(diào)用,會(huì)觸發(fā)兩個(gè)部件的paint()的執(zhí)行。

這意味著對(duì)于Swing部件來(lái)說(shuō),update()不再被調(diào)用。

雖然repaint()方法導(dǎo)致了對(duì)paintImmediately()的調(diào)用,它不考慮"回調(diào)"繪圖,并且客戶端的繪畫(huà)代碼也不會(huì)放置到 paintImmediately()方法里面。實(shí)際上,除非有特殊的原因,根本不需要超載paintImmediately()方法。

Swing繪畫(huà)準(zhǔn)則
Swing開(kāi)發(fā)人員在寫(xiě)繪畫(huà)代碼時(shí)應(yīng)該理解下面的準(zhǔn)則:
1。對(duì)于Swing部件,不管是系統(tǒng)-觸發(fā)還是程序-觸發(fā)的請(qǐng)求,總會(huì)調(diào)用paint()方法;而update()不再被Swing部件調(diào)用。
2。程序可以通過(guò)repaint()觸發(fā)一個(gè)異步的paint()調(diào)用,但是不能直接調(diào)用paint()。
3。對(duì)于復(fù)雜的界面,應(yīng)該調(diào)用帶參數(shù)的repaint(),這樣可以僅僅更新由該參數(shù)定義的區(qū)域;而不要調(diào)用無(wú)參數(shù)的repaint(),導(dǎo)致整個(gè)部件重畫(huà)。
4。Swing中實(shí)現(xiàn)paint()的3個(gè)要素是調(diào)用3個(gè)分離的回調(diào)方法:
◆paintComponent()
◆paintBorder()
◆paintChildren()
Swing部件的子類,如果想執(zhí)行自己的繪畫(huà)代碼,應(yīng)該把自己的繪畫(huà)代碼放在paintComponent()方法的范圍之內(nèi)。(不要放在paint()里面)。
5。Swing引進(jìn)了兩個(gè)屬性來(lái)最大化的改善繪畫(huà)的性能:
◆opaque: 部件是否要重畫(huà)它所占據(jù)范圍中的所有像素位?
◆optimizedDrawingEnabled: 是否有這個(gè)部件的子孫與之交迭?
6。如果Swing部件的(遮光)opaque屬性設(shè)置為true,那就表示它要負(fù)責(zé)繪制它所占據(jù)的范圍內(nèi)的所有像素位(包括在paintComponent()中清除它自己的背景),否則會(huì)造成屏幕垃圾。
7。如果一個(gè)部件的遮光性(opaque)和optimizedDrawingEnabled屬性有一個(gè)被設(shè)置為false,將導(dǎo)致在每個(gè)繪畫(huà)操作中要執(zhí)行更多的處理,因此我們推薦的明智的方法是同時(shí)使用透明并且交迭部件。
8。使用UI代理(包括JPanel)的Swing部件的擴(kuò)展類的典型作法是在它們自己的paintComponent()的實(shí)現(xiàn)中調(diào)用super.paintComponent()。因?yàn)閁I代理可以負(fù)責(zé)清除一個(gè)遮光部件的背景,不過(guò)這一操作需要根據(jù)規(guī)則#5中的設(shè)定來(lái)決定。
9。Swing通過(guò)JComponent的doubleBuffered屬性支持內(nèi)置的雙緩沖,所有的Swing部件該屬性默認(rèn)值是true,然而把Swing容器的遮光設(shè)置為true有一個(gè)整體的構(gòu)思,把該容器上的所有輕量級(jí)子孫的屬性打開(kāi),不管它們各自的設(shè)定。
10。強(qiáng)烈建議為所有的Swing部件使用雙緩沖。
11。界面復(fù)雜的部件應(yīng)該靈活地運(yùn)用剪切框來(lái),只對(duì)那些與剪切框相交的區(qū)域進(jìn)行繪畫(huà)操作,從而減少工作量。

以上是“AWT和Swing繪畫(huà)的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI