您好,登錄后才能下訂單哦!
小編給大家分享一下輕量級Swing組件的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
在Swing頂層重量級容器組件的一個繪制場景中,可以看到是經(jīng)由awt-windows eventloop到了底層事件后觸發(fā)paint繪制;然而對輕量級Swing組件,其paint都是通過java代碼中對repaint調(diào)用而觸發(fā),其會向RepaintManager.addDirtyRegion,同時 scheduleProcessingRunnable。這是整個GUI生命周期內(nèi)對繪制的兩種不同的觸發(fā)方式,但觸發(fā)后的處理都是交由 RepaintManager。
回過頭去看,JFrame被構(gòu)造的時候就會創(chuàng)建root pane, layered pane,content pane, glass pane等,這些沒有對等體的輕量級Swing組件在構(gòu)造時都將repaint。雖然在創(chuàng)建windows對等窗口之前這些Swing組件就已經(jīng)在要求繪制,但是RepaintManager能夠協(xié)調(diào)好這個步調(diào)(具體即是當(dāng)收到repaint請求時要判斷情況,像這時的請求因?yàn)轫攲尤萜鬟€沒有繪制則不會記錄到重畫區(qū))。所以最終效果就是在peer.pshow的時候只能看到一個空窗口,隨后底層消息到來后通過paint回調(diào)畫這些子組件,***hello world才顯示出來。如果眼神好,能夠看出這有一個“閃爍”。
這是一個最簡單的Swing應(yīng)用程序的基本運(yùn)行機(jī)制分析,下面再具體分析。
Swing的GUI總是由頂層容器組件和輕量級Swing組件組合建立,頂層容器和其他組件區(qū)別主要在于頂層容器沒有自身的paint邏輯。所有頂層容器都是通過使用底層系統(tǒng)API來繪制對等體的方式進(jìn)行paint,自身沒有java2d的paint邏輯實(shí)現(xiàn),對等體畫成什么樣頂層容器就是什么樣,它只是可以控制對等體的一些可配顯示屬性。所以效果就是比如在windows平臺上畫一個jframe,除在桌面上顯示一個窗口還會在任務(wù)欄上顯示一個條目。Swing的 4個頂層容器都是在addNotify時才會getToolkit().createPeer(this)(Frame/Dialog/Window), 而addNotify并不是在構(gòu)造時被調(diào)用,而是在pack/show或setvisible(這3個所謂的realized具現(xiàn)化方法)時被調(diào)用。創(chuàng)建了對等體peer后還要通過peer.pShow(show/setVisible(true)調(diào)用)調(diào)用才會要求底層系統(tǒng)進(jìn)行顯示(所以只有pack是不會顯示窗口的)。在顯示窗口后底層消息隊列得到通知,此后隨著窗口被最小化后恢復(fù)或被遮蓋后恢復(fù)等系統(tǒng)操作后同樣能從底層消息得到通知,這時的監(jiān)聽處理將有選擇地通知給RepaintManager一個重畫請求進(jìn)行窗口內(nèi)容-子組件重畫。
而輕量級Swing組件將繪制有關(guān)的職責(zé)都委托給了ui成員對象,ui對象使用JAVA2D API 進(jìn)行繪制,paint成什么樣那就是這個組件的樣子。具體就是在構(gòu)造的時候即要 updateUI{setUI(UIManger.getUI(this))}。UIManger會根據(jù)當(dāng)前L&F的選擇,根據(jù) this.uiClassID來得到ui成員類并建立實(shí)例,以后的paint回調(diào)等都推托給ui成員類paint,這也算是一種策略模式。Setui的過程中除了保存這個ui實(shí)例外,將repaint來通知RepaintManager進(jìn)行paint回調(diào)完成組件繪制。輕量級Swing組件在addNotify時也會去創(chuàng)建對等體getToolkit().createPeer(this)( LightWeightPeer),但這個peer的實(shí)現(xiàn)(NullComponentPeer)是個空殼子,只是作為一個輕量級組件的標(biāo)記,以后的很多事件處理等都要判斷peer是否instance of LightWeightPeer從而能夠進(jìn)行不同處理。同樣的Addnotify也不是在構(gòu)造時被調(diào)用,而是在被加入container時被調(diào)用。
注意:構(gòu)造方法本身就是狀態(tài)模式的***狀態(tài),所以GUI組件的構(gòu)造方法里就應(yīng)該要努力完成自身的繪制來符合自己的地位。輕量級組件就是按這個意義在構(gòu)造方法里去通知repaintmanager進(jìn)行自身繪制的,但是頂層容器卻將真正的繪制意圖createPeer延遲到了具現(xiàn)方法里。這是因?yàn)槭紫纫粋€合乎思維的表達(dá)邏輯是先有容器,再將子組件向容器里添加,所以最頂層容器總是先行構(gòu)造出來,然后再被一層層地追加輕量級子組件。如果最頂層容器在構(gòu)造時就去具現(xiàn),則就要求后續(xù)的構(gòu)造都應(yīng)該在EDT中進(jìn)行,而且每次add子組件都要導(dǎo)致revalidate;但若將最頂層容器的繪制分離延遲到具現(xiàn)方法里,則可以表達(dá)是在容器里盛滿了要顯示的子組件后再一股腦具現(xiàn)繪制出來的概念,類似于在進(jìn)行一次web頁面的完整加載,然后注意在具現(xiàn)方法執(zhí)行后如果要操作組件都在EDT中進(jìn)行即可,而且頂層容器提供一個特有的 pack方法,用來一次性對所有子組件驗(yàn)證大小位置進(jìn)行重布局,pack之后再show,這樣的一次性計算展現(xiàn)是最有效率的。
頂層容器和輕量級組件就是這樣誕生并繪制的,在此后的生命周期里,都將按事件監(jiān)聽機(jī)制完成GUI隨需而變,無論是系統(tǒng)事件,還是因?yàn)閞epaint調(diào)用主動post事件,事件到來后再在EDT中執(zhí)行監(jiān)聽器里的paint繪制。Swing已經(jīng)提供的頂層容器和輕量級組件因各自的定義已經(jīng)注冊了各自的paint監(jiān)聽,開發(fā)人員可以再行維護(hù)或按此模式開發(fā)新組件從而滿足應(yīng)用的需要。比如,jbutton默認(rèn)有mousepress listener,在mousepress事件到來后,監(jiān)聽響應(yīng)中會設(shè)置鼠標(biāo)顏色加深來表示按下,然后再調(diào)用repaint要求重畫,隨后在EDT中執(zhí)行 jbutton的paint回調(diào),此時按深顏色繪制,于是一個被按下的效果就出來了。
下面在具體分析各類事件的處理。
對于頂層容器的受底層事件消息的觸發(fā),當(dāng)?shù)玫降耐ㄖ且驗(yàn)閑xpose暴露隱藏區(qū)(暴露被遮蔽的部分或恢復(fù)最小化或***次繪制等)時,處理過程會涉及到雙緩存的處理,即如果可能,直接使用緩存中的舊圖像信息進(jìn)行覆蓋而不再重新繪制。
所謂雙緩存機(jī)制是將一整片的顯示內(nèi)容暫時寫入一張內(nèi)存空間里,然后一次性內(nèi)存拷入顯示區(qū)來進(jìn)行顯示,這樣處理是因?yàn)槿绻苯訉懭腼@示區(qū),隨著顯示區(qū)被該寫入線程逐漸寫入,可能經(jīng)歷多次屏幕刷新,導(dǎo)致每次刷新都形成過程圖像,給人眼造成閃爍感覺;同時一個副收益就是可以針對每個窗口都做緩存待用(而不僅僅是針對一個屏幕雙緩存),當(dāng)窗口被遮擋的部分重現(xiàn)時直接拷貝緩存來覆蓋,不用再執(zhí)行繪畫邏輯,提高了效率。
現(xiàn)在的OS一般都提供雙緩存機(jī)制支持,如果底層系統(tǒng)自身支持以每個窗口為單位做雙緩存,則該expose消息將被本地處理,不需要通知進(jìn)行子組件的繪制;如果底層不支持,則該消息會到達(dá)wcomponetpeer.handleexpose中進(jìn)行回調(diào)處理,此時Swing機(jī)制下有一個參數(shù)控制的雙緩存機(jī)制可以提供。這里的參數(shù)控制需要從RepaintManager的構(gòu)造過程說起。
首先RepaintManager可以通過static setCurrentManager(SomeCurrentManager)來進(jìn)行全局指定。默認(rèn)情況使用 currentRepaintManager(){new RepaintManager(BUFFER_STRATEGY_TYPE)}得到一個延遲創(chuàng)建的單例。RepaintManager有一段靜態(tài)類初始化過程,涉及到雙緩存設(shè)置:
static{
nativeDoubleBuffering="true".equals(AccessController.doPrivileged(
newGetPropertyAction("awt.nativeDoubleBuffering")));//JVM的啟動參數(shù)控制,默認(rèn)false
Stringbs=AccessController.doPrivileged(
newGetPropertyAction("swing.bufferPerWindow"));//是否每窗口緩存。
if(headless){
BUFFER_STRATEGY_TYPE=BUFFER_STRATEGY_SPECIFIED_OFF;
}
elseif(bs==null){
BUFFER_STRATEGY_TYPE=BUFFER_STRATEGY_NOT_SPECIFIED;
}
elseif("true".equals(bs)){
BUFFER_STRATEGY_TYPE=BUFFER_STRATEGY_SPECIFIED_ON;
}
else{
BUFFER_STRATEGY_TYPE=BUFFER_STRATEGY_SPECIFIED_OFF;
}
}
privateRepaintManager(shortbufferStrategyType){
//Ifnativedoublebufferingisbeingused,doNOTuse
//Swingdoublebuffering.
doubleBufferingEnabled=!nativeDoubleBuffering;
this.bufferStrategyType=bufferStrategyType;
}
publicvoidsetDoubleBufferingEnabled(booleanaFlag){
doubleBufferingEnabled=aFlag;
privatesynchronizedPaintManagergetPaintManager(){
if(paintManager==null){
PaintManagerpaintManager=null;
if(doubleBufferingEnabled&&!nativeDoubleBuffering){
switch(bufferStrategyType){
caseBUFFER_STRATEGY_NOT_SPECIFIED:
if(((SunToolkit)Toolkit.getDefaultToolkit()).
useBufferPerWindow()){//windows下是否禁用vistadwm,
在沒有聲明bufferPerWindow的情況下由windows系統(tǒng)特性確定paintmanager。paintManager=newBufferStrategyPaintManager();
}
break;
caseBUFFER_STRATEGY_SPECIFIED_ON:
paintManager=newBufferStrategyPaintManager();
break;
default:
break;
}
}
//nullcasehandledinsetPaintManager
setPaintManager(paintManager);
}
returnpaintManager;
}
voidsetPaintManager(PaintManagerpaintManager){
if(paintManager==null){
paintManager=newPaintManager();
}
}
以上是“輕量級Swing組件的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。