![UCGUI窗體管理及消息處理機(jī)制分析講課講稿_第1頁](http://file4.renrendoc.com/view/412b795c89d917f6d9aef6cf62dc4376/412b795c89d917f6d9aef6cf62dc43761.gif)
![UCGUI窗體管理及消息處理機(jī)制分析講課講稿_第2頁](http://file4.renrendoc.com/view/412b795c89d917f6d9aef6cf62dc4376/412b795c89d917f6d9aef6cf62dc43762.gif)
![UCGUI窗體管理及消息處理機(jī)制分析講課講稿_第3頁](http://file4.renrendoc.com/view/412b795c89d917f6d9aef6cf62dc4376/412b795c89d917f6d9aef6cf62dc43763.gif)
![UCGUI窗體管理及消息處理機(jī)制分析講課講稿_第4頁](http://file4.renrendoc.com/view/412b795c89d917f6d9aef6cf62dc4376/412b795c89d917f6d9aef6cf62dc43764.gif)
![UCGUI窗體管理及消息處理機(jī)制分析講課講稿_第5頁](http://file4.renrendoc.com/view/412b795c89d917f6d9aef6cf62dc4376/412b795c89d917f6d9aef6cf62dc43765.gif)
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、Good is good, but better carries it.精益求精,善益求善。UCGUI窗體管理及消息處理機(jī)制分析-UCGUI窗體管理及消息處理機(jī)制分析-多對話框/模態(tài)窗體/透明窗體支持分析作者:ucgui日期:2005-09-08v2005-06-30完成來源:版本:v版本修改說明時(shí)間v實(shí)現(xiàn)UCGUI中多對話框支持。2005-06-30v增加UCGUI中各種基本消息介紹。增加窗體消息LOOP機(jī)制介紹。增加對話框結(jié)構(gòu)說明及其消息LOOP處理移到MainTask函數(shù)中由用戶處理的原因剖析,并詳細(xì)分析了對話框中按鈕的點(diǎn)擊消息傳送到用戶自定義對話框回調(diào)函數(shù)中處理的傳遞流程。增加外部輸入
2、設(shè)備消息處理機(jī)制介紹。如滑動(dòng)操作外設(shè)MOUSE及觸摸屏輸入消息(WM_TOUCH)的處理機(jī)制,及按鍵式操作外設(shè)消息(WM_KEY)處理機(jī)制。增加一種更簡單的多對話框支持的方法及說明。增加模態(tài)對話框?qū)崿F(xiàn)原理分析。增加透明窗體實(shí)現(xiàn)原理分析。2005-09-08問題的提出:求助關(guān)于對話框處理程序中,想在OK按鈕按下后想彈出一個(gè)消息框,該怎么做?直接加在程序中好像不行,如何讓消息框彈出后成為模態(tài)窗體呢?請版主幫幫忙。解析在UCGUI中,對話框只支持單個(gè)對話框窗體,不支持多個(gè)獨(dú)立的對話框,現(xiàn)在我們從其源碼來分析一下它為什么支持單個(gè)對話框窗體以及如何改進(jìn)它以支持多個(gè)獨(dú)立對話框,要講解這個(gè)問題我們必須首先理
3、解UCGUI中的窗體消息LOOP,沒有消息LOOP窗體就是死水一潭,不能接受任何外界的輸入,只是一個(gè)畫在那里的圖畫而已。聲明本文中提到的源碼均為UCGUI3.24版源碼,新版UCGUI源碼會(huì)有改動(dòng),請下載本文示例代碼來結(jié)合閱讀本文。摘要:本文主要介紹了UCGUI中的對話框的消息處理機(jī)制,并指出在現(xiàn)有UCGUI上如何增加多窗體支持,并在分析解決問題時(shí)著重介紹了其輸入設(shè)備消息WM_TOUTCH及WM_KEY兩類消息處理方法,并同時(shí)初步指出一種在UCGUI中實(shí)現(xiàn)模態(tài)對話框以及透明窗體的原理說明,不還有窗體重畫消息WM_PAINT消息處理原理。一、各種基本消息介紹及處理流程-對話框內(nèi)部消息流轉(zhuǎn)及外部消
4、息LOOP分析.UCGUI是采用的消息驅(qū)動(dòng)的,它專門有對外的一套收集消息的接口,我在模似器中,就是通過LCD模擬顯示屏窗口的MOUSE消息,將MOUSE消息傳入到這個(gè)接口中,以驅(qū)動(dòng)UCGUI中的窗體的。UCGUI中的消息驅(qū)動(dòng)其實(shí)與WINDOWS的是類似的,幾種基本的消息與WINDOWS是一樣的,但UCGUI的更簡單且消息更少,對于一些消息的處理得也很簡化,沒有WINDOWS那么多的消息種類及復(fù)雜處理。在WINDOWS中,如我們處理按鈕控件的點(diǎn)擊事件的是在WM_COMMAND消息中,通過按鈕的標(biāo)志ID來區(qū)分不同的按鈕,所以按鈕標(biāo)志ID必須不同的,否則無法區(qū)別開(除非不在父窗體的WM_COMMAN
5、D消息中處理)。UCGUI中一些基本的消息如下:WM_CREATE-窗體創(chuàng)建消息,每創(chuàng)建一個(gè)窗體完后都會(huì)向該窗體發(fā)送此消息,如WM_CreateWindowAsChild創(chuàng)建完窗體均會(huì)發(fā)一此消息,但在UCGUI中對于此消息的很少處理,如果用戶想在對話框之后做些初始化操作或是創(chuàng)建其它子窗體的動(dòng)作,可以處理此消息,不過對話框一般有專門的初始化消息WM_INIT_DIALOG,它是在創(chuàng)建對話框后發(fā)送的。WM_SHOW-顯示窗體消息,此消息在UCGUI中各控件窗體內(nèi)均未作處理,如果你通過消息發(fā)送函數(shù)來發(fā)送這類沒有在UCGUI中各窗體中處理的消息,是沒有有什么響應(yīng)的,不要感到奇怪。要顯示窗體一般是通過W
6、M_ShowWindow()函數(shù)實(shí)現(xiàn)的,這個(gè)函數(shù)做的也就是改變窗體顯示標(biāo)志W(wǎng)M_SF_ISVIS,并使窗體矩形區(qū)域無效WM_InvalidateWindow()以產(chǎn)生重畫消息。WM_SET_ENABLE-設(shè)置窗體不能使用消息,UCGUI中有一種復(fù)選框?yàn)椴豢筛淖兊模沁@個(gè)功能也不完全,如果你對著UCGUI中的按鈕使用WM_DisableWindow()來設(shè)置其無效,按鈕照樣還是可以使用,不過要改進(jìn)這些小毛病還是很容易的,這里只是提醒大家UCGUI中很多沒有實(shí)現(xiàn)的小地方,不要到時(shí)候使用時(shí)感到很奇怪,感覺到奇怪時(shí)最好去看看源碼,看看源碼中是否實(shí)現(xiàn)了此功能,不要郁悶。WM_PAINT-窗體重畫消息,
7、當(dāng)窗體所在區(qū)域全部或是部分區(qū)域無效時(shí),系統(tǒng)將會(huì)發(fā)出該重畫消息,將無效區(qū)域重畫,但UCGUI中的處理比較簡單,都是將窗體全部區(qū)域重畫;如果用戶自己想在窗體上畫上一些信息,一般都在在該消息當(dāng)中畫,UCGUI中的各種提供的系統(tǒng)控件都必須在其系統(tǒng)的提供的消息回調(diào)函數(shù)中處理此消息來畫出控件。當(dāng)由外部輸入操作引起無效窗體區(qū)域產(chǎn)生時(shí),系統(tǒng)都會(huì)在消息處理中發(fā)送該消息到窗體消息回調(diào)函數(shù)中,以重畫此窗體,在下面講解消息循環(huán)機(jī)制時(shí)將會(huì)著重講解到該消息的產(chǎn)生。透明窗體-經(jīng)常有朋友想知道在UCGUI中如何實(shí)現(xiàn)透明窗體,透明窗窗體顯示在前臺(tái)時(shí),可以看到部分位于其窗體后的內(nèi)容,即透過窗體可以看到窗體背后的圖象。在UCGUI
8、中有關(guān)于透明窗體的設(shè)置選項(xiàng),可是沒有實(shí)現(xiàn)此功能,其實(shí)要實(shí)現(xiàn)原理如下:第一透明窗體及其所有子窗體都必須透明處理;第二是對于所有有透明屬性的窗體,在繪圖時(shí)必須使用透明填充功能的矩形填充函數(shù),主要是修改窗體的WM_PAINT消息中畫窗體時(shí)的矩形填充函數(shù)為透明的矩形填充;第三透明的矩形填充函數(shù)的實(shí)現(xiàn),通常情況下的矩形填充是以當(dāng)前前景色來填充,那么關(guān)鍵就是實(shí)現(xiàn)畫點(diǎn)函數(shù)的透明填充,要使一個(gè)透明,可以取當(dāng)前顯存中存點(diǎn)的點(diǎn)的RGB顏色,然后再與當(dāng)前要畫的顏色按照一個(gè)比例進(jìn)行混合得一個(gè)新的RGB值,再將此值畫以屏幕上就可能實(shí)現(xiàn)透明填充的效果。WM_TOUCH-處理類似MOUSE的滑動(dòng)操作方式的輸入外設(shè)的消息,如
9、觸摸屏一般都是將其消息從硬件接收到后轉(zhuǎn)化為該消息形式發(fā)送出去,該消息中必須包含消息在屏幕中的發(fā)生位置坐標(biāo)及輸入設(shè)備狀態(tài)(按下狀態(tài)或彈起狀態(tài)),此消息在任務(wù)消息循環(huán)中循環(huán)處理,一旦產(chǎn)生就會(huì)發(fā)送給當(dāng)前焦點(diǎn)窗體,在后面將詳細(xì)講解該消息的處理機(jī)制。WM_KEY-處理類似KEY的按鍵式操作的輸入外設(shè)的消息,消息中必須包含按鍵的按下或彈起狀態(tài),此消息也是在任務(wù)消息循環(huán)中循環(huán)處理,一旦產(chǎn)生就會(huì)發(fā)送給當(dāng)前焦點(diǎn)窗體,講解消息LOOP時(shí)再詳細(xì)介紹。WM_SET_FOCUS-講到剛才上面的兩個(gè)消息時(shí),就反復(fù)提到了當(dāng)前焦點(diǎn)窗體的概念,所有外部輸入設(shè)備消息都是發(fā)送給當(dāng)前焦點(diǎn)窗體的,用戶可以通過此消息來設(shè)定當(dāng)前的焦點(diǎn)窗體
10、。外部輸入操作也會(huì)改變當(dāng)前焦點(diǎn)窗體,如點(diǎn)擊某窗體時(shí)會(huì)在該窗體的WM_TOUCH消息處理中設(shè)置該窗體本身為當(dāng)前焦點(diǎn)窗體;當(dāng)在對話框中按鍵TAB鍵時(shí),同樣也可以將焦點(diǎn)在對話框上各控件間切換,這是在對話框的WM_KEY消息中處理實(shí)現(xiàn)的了解一下WM_SetFocusOnNextChild()函數(shù),是根據(jù)創(chuàng)建對話框時(shí)指定的資源定義數(shù)組中的順序來切換的,并沒有WIN下面指定的TabIndex這樣一個(gè)值來指定次序的值。WM_NOTIFY_PARENT-這個(gè)消息將子窗體的外設(shè)輸入的消息傳送到它的父窗體,因?yàn)橐话愕那闆r下消息都是在父窗體中統(tǒng)一處理的,如對話框中的按鈕點(diǎn)擊事件,一般都是在用戶自定義的窗體消息處理函
11、數(shù)中處理,所以就必須要子窗體將獲取的輸入外設(shè)的消息傳送給父窗體,這樣才能在父窗體中進(jìn)行子窗體的點(diǎn)擊事件消息的處理,這個(gè)消息的機(jī)制類似WIN下面的WM_COMMAND消息,處理該消息時(shí)通過控件ID來區(qū)別不同的控件,通過消息中的通知碼來區(qū)別控件被操作的各種狀態(tài),具體這個(gè)消息的詳細(xì)說明請參見后面的分析。WM_DELETE-要?jiǎng)h除窗體時(shí)發(fā)送的消息,主要清除窗體數(shù)據(jù)結(jié)構(gòu)所占用內(nèi)存,此消息主要由WM_DeleteWindow()函數(shù)發(fā)送了,如點(diǎn)擊OK按鈕關(guān)閉對話框時(shí),最終會(huì)調(diào)用此函數(shù)來刪除窗體,不過UCGUI中沒有最大化最小化關(guān)閉等系統(tǒng)功能按鈕。最基礎(chǔ)窗體結(jié)構(gòu)注解如下,在該結(jié)構(gòu)中有兩個(gè)很重要的成員,hNe
12、xtLin是記載窗體的下一個(gè)窗體,這個(gè)成員用于遍歷所有已經(jīng)創(chuàng)建的窗體;hNext是記載窗體下一個(gè)兄弟窗體,這個(gè)成員用于遍歷每個(gè)窗體對應(yīng)的子窗體;這個(gè)結(jié)構(gòu)是最基礎(chǔ),一般的控件在這個(gè)結(jié)構(gòu)之上還會(huì)有一些擴(kuò)展的結(jié)構(gòu),如按鈕對應(yīng)有BUTTON_Obj結(jié)構(gòu)。typedefstructWM_OBJ_structWM_Obj;structWM_OBJ_structGUI_RECTRect;/*窗體矩形區(qū)域*/GUI_RECTInvalidRect;/*窗體無效矩形區(qū)域*/WM_CALLBACK*cb;/*窗體消息回調(diào)函數(shù)*/WM_HWINhNextLin;/*窗體下一個(gè)窗體句柄*/WM_HWINhParent
13、;/*父窗體句柄*/WM_HWINhFirstChild;/*第一子窗體句柄*/WM_HWINhNext;/*下一個(gè)兄弟窗體句柄*/U16Status;/*窗體當(dāng)前狀態(tài)*/;WIDGET_HandleActive()基礎(chǔ)控件共通消息處理,在大部分的UCGUI控件中都會(huì)在消息回調(diào)函數(shù)的頭部進(jìn)行這個(gè)調(diào)用,如果處理了消息后,就直接退出消息回調(diào)函數(shù)的調(diào)用。這個(gè)函數(shù)中處理如下消息:WM_GET_ID返窗體控件標(biāo)志ID.WM_SET_FOCUS設(shè)置當(dāng)前窗體為焦點(diǎn)窗體,設(shè)置完后還必須向該窗體的父窗體發(fā)送一個(gè)WM_NOTIFY_CHILD_HAS_FOCUS消息讓其父窗體更新它記載的當(dāng)前焦點(diǎn)子窗體.WM_GE
14、T_HAS_FOCUS獲取當(dāng)前窗體是否為焦點(diǎn)窗體.WM_SET_ENABLE設(shè)置窗體為不可用窗體.WM_GET_ACCEPT_FOCUS獲取當(dāng)前窗體是否可設(shè)置為焦點(diǎn)窗體.WM_GET_INSIDE_RECT返回窗體內(nèi)框矩形,如按鈕有3D效果時(shí)會(huì)有效果邊框?qū)挾?,?nèi)框矩形就是窗體矩形被邊框剪裁后的矩形.WM_DefaultProc()-窗體默認(rèn)消息處理函數(shù),UCGUI中提供一些基礎(chǔ)的控件,這些控件有些共通的消息均在此處理,如下:WM_GETCLIENTRECT獲取窗體矩形區(qū)域,相對于矩形自身WM_GETORG獲取窗體矩形左上角坐標(biāo).WM_GET_INSIDE_RECT獲取窗體矩形區(qū)域,相對屏幕.W
15、M_GET_CLIENT_WINDOW獲取窗體客戶區(qū)子窗體句柄,如對話框的中的子窗體FrameWin即為此種窗體.WM_KEY銨鍵消息處理,通知父窗體子窗體的按鍵消息,有些控件自己要處理這個(gè)消息,如Edit控件處理完此消息后就沒有再調(diào)用WM_DefaultProc(),從而沒有將WM_KEY消息通父窗體;如Button控件,根本沒有對此消息進(jìn)行處理,直接是通過默認(rèn)處理發(fā)給了父窗體處理;有些控件如Checkbox自己處理該消息,同時(shí)也調(diào)用默認(rèn)消息處量將此消息通知父窗本,此種消息源窗體為子控件,目標(biāo)窗體為父窗體。如此處理WM_KEY消息完全是UCGUI中如此做,在WIN中并沒有這樣做.WM_GET
16、_BKCOLOR獲取窗體背景色,在此未實(shí)現(xiàn),返回0 xfffffff值,但FrameWin窗體實(shí)現(xiàn)了此消息處理.在UCGUI的對話框的窗口消息處理函數(shù)中OK按鈕的點(diǎn)擊事件,UCGUI的處理方法與WIN下面是不同,它在WM_NOTIFY_PARENT消息中處理片段如下:caseWM_NOTIFY_PARENT:Id=WM_GetId(pMsg-hWinSrc);/*Idofwidget*/NCode=pMsg-Data.v;/*Notificationcode*/switch(NCode)caseWM_NOTIFICATION_RELEASED:/*Reactonlyifreleased*/if
17、(Id=GUI_ID_OK)/*OKButton*/GUI_MessageBox(Thistextisshownninamessagebox,Caption/Title,GUI_MESSAGEBOX_CF_MOVEABLE);if(Id=GUI_ID_CANCEL)/*CancelButton*/GUI_EndDialog(hWin,1);break;break;UCGUI中的消息種類不多,只有差不多不到二十種,但對于嵌入式系統(tǒng)來說已經(jīng)完全足夠了,用戶可以自定義消息(從WM_USER起)。WM_NOTIFY_PARENT這個(gè)消息是由子窗體傳送給父窗體的,由消息的名字也可以看出這一點(diǎn),OK按鈕也
18、是一個(gè)窗體,當(dāng)MOUSE點(diǎn)擊在它上面時(shí),UCGUI首先會(huì)傳遞一個(gè)WM_TOUCH消息到OK按鈕的窗口消息處理函數(shù),OK按鈕是一個(gè)系統(tǒng)提供的控件,系統(tǒng)已經(jīng)提供了一個(gè)默認(rèn)的消息的窗口消息處理函數(shù),這個(gè)函數(shù)會(huì)處理大部分的默認(rèn)窗口消息并隨后將此消息轉(zhuǎn)發(fā)給父窗體,即WM_NOTIFY_PARENT消息,它是由函數(shù)WM_NotifyParent(hObj,Notification)實(shí)現(xiàn)的.WM_TOUCH消息在按鈕的消息處理函數(shù)_BUTTON_Callback中的_OnTouch函數(shù)中處理,在處理過程完后會(huì)調(diào)用WM_NotifyParent向按鈕的父窗體發(fā)WM_NOTIFY_PARENT消息告訴對話框回調(diào)
19、函數(shù)按鈕被點(diǎn)擊了,這個(gè)過程再說詳細(xì)一點(diǎn)是這樣的:點(diǎn)擊OK按鈕.產(chǎn)生按鈕WM_TOUCH消息.UCGUI中的消息LOOP調(diào)用按鈕默認(rèn)的按鈕窗口消息處理函數(shù)_BUTTON_Callback._OnTouch默認(rèn)處理按鈕點(diǎn)擊并發(fā)送給父窗體WM_NOTIFY_PARENT消息,這里要注意MOUSE點(diǎn)擊后,有三種情況:第一種是點(diǎn)擊后在按鈕范圍內(nèi)彈出MOUSE,這種情況下,會(huì)送的消息中還有一個(gè)通知碼就是WM_NOTIFICATION_RELEASED;第二種情況是點(diǎn)擊拖到按鈕范圍外彈起MOUSE,此時(shí)通知碼是WM_NOTIFICATION_MOVED_OUT;第三種情況是點(diǎn)擊后一直未彈起MOUSE的過程中
20、消息通知碼為WM_NOTIFICATION_CLICKED;在這個(gè)函數(shù)中還會(huì)處理設(shè)置按鈕點(diǎn)擊后MOUSE至未彈起前的按下狀態(tài),這樣在按鈕下一次畫出時(shí)就會(huì)以按下的狀態(tài)顯示出來.默認(rèn)的對話框窗體消息處理函數(shù)_FRAMEWIN_Callback收到WM_NOTIFY_PARENT消息并最終傳送該消息到用戶自己定義的對話框消息處理函數(shù),這里要注意的一點(diǎn)是,其實(shí)對話框主要是由一個(gè)FrameWin子窗體構(gòu)成的,這個(gè)子窗體大小為對話框指定的大小,對話框上的其它控件是都是FrameWin的子窗體,由_FRAMEWIN_Callback傳送的消息首先是傳送到對話框的默認(rèn)窗體消息回調(diào)函數(shù)_cbDialog,然后再
21、經(jīng)它傳送到用戶自定義的窗體回調(diào)函數(shù)當(dāng)中。用戶在自己的對話框消息處理函數(shù)中處理WM_NOTIFY_PARENT消息,即按鈕的點(diǎn)擊消息,該消息參數(shù)中含有按鈕的ID及操作狀態(tài),如果通知碼是WM_NOTIFICATION_RELEASED,此時(shí)證明一次點(diǎn)擊事件完成。voidWM_NotifyParent(WM_HWINhWin,intNotification)WM_MESSAGEMsg;Msg.MsgId=WM_NOTIFY_PARENT;Msg.Data.v=Notification;WM_SendToParent(hWin,&Msg);這個(gè)函數(shù)相當(dāng)簡單,其主要還是WM_SendToParent這個(gè)
22、函數(shù)的調(diào)用,這個(gè)函數(shù)再調(diào)用voidWM_SendMessage(WM_HWINhWin,WM_MESSAGE*pMsg),這個(gè)函數(shù)是最基本的一個(gè)消息發(fā)送處理函數(shù),它的第一個(gè)參數(shù)指定了接受這個(gè)要處理的消息的句柄,第二個(gè)指定了是什么消息。這個(gè)函數(shù)的主要作用是調(diào)用相應(yīng)窗口的消息處理函數(shù)來處理消息,如果你有消息要發(fā)送給指定的窗體處理,那么也可以使用這個(gè)函數(shù)。在上面,我們剛剛分析了在對話框內(nèi)部消息處理的流轉(zhuǎn),其中分析了我們在自己指定的對話框消息處理函數(shù)當(dāng)中是如何可以獲得按鈕的點(diǎn)擊消息并進(jìn)行處理的,現(xiàn)在我們就再來分析一下對話框外面的消息接收:首先是來了解一下GUI_ExecDialogBox函數(shù),這個(gè)函數(shù)
23、有幾個(gè)參數(shù):第一個(gè)是對話框的資源定義數(shù)組,這個(gè)數(shù)組定義了對話框的組成子窗體,其中數(shù)組第一個(gè)成員必須是FrameWin窗體,數(shù)組每一個(gè)成員記載了創(chuàng)建子窗體所用函數(shù)/子窗體Caption/子窗體標(biāo)志ID/子窗體的位置及寬高/創(chuàng)建窗體時(shí)樣式標(biāo)志/額外傳送的參數(shù).第二個(gè)參數(shù)是上述的數(shù)組的大小.第三個(gè)參數(shù)是用戶指定的對話框窗體消息回調(diào)函數(shù)指針.第四個(gè)參數(shù)是對話框的父窗體,默認(rèn)為0.第五、六參數(shù)指定對話框的左上角屏幕位置.GUI_ExecDialogBox主要完成如下幾件事:根據(jù)傳進(jìn)來的對話框資源定義數(shù)組創(chuàng)建對話框及對話框中的子窗體.根據(jù)傳進(jìn)來的窗口消息處理函數(shù),記載到一全局變量保存,當(dāng)這個(gè)全局變量中記載
24、的函數(shù)指針為非空時(shí),執(zhí)行消息LOOP,消息LOOP中會(huì)將當(dāng)前的MOUSE及KEY消息發(fā)送給當(dāng)前焦點(diǎn)窗體.當(dāng)對話框關(guān)閉時(shí),記載對話窗體消息回調(diào)函數(shù)的全局變量會(huì)被清為0,此時(shí)消息LOOP就會(huì)退出,對話框結(jié)束.二、發(fā)現(xiàn)存在的問題-點(diǎn)擊OK后無論先關(guān)閉消息框還是對話框,另一個(gè)不再響應(yīng).點(diǎn)擊對話框的OK后彈出消息框,會(huì)出現(xiàn)當(dāng)按下對話框的Cancel關(guān)閉對話框后,彈出的消息框就沒有任何響應(yīng)的情況.或者是關(guān)閉掉彈出的消息框,對話框就沒有任何響應(yīng)的情形:從外部粗步分析的原因是調(diào)用MainTask的線程已經(jīng)退出了,這個(gè)線程是在模擬器中開啟的專門用于運(yùn)行GUI任務(wù)的線程,它的線程函數(shù)是Thread,Thread函
25、數(shù)里調(diào)用main,main中再調(diào)用MainTask,所以該線程退出后也就代表UCGUI任務(wù)已經(jīng)結(jié)束了。這是從模擬器的角度來分析,現(xiàn)在我們分析一下為什么MainTask的調(diào)用線程會(huì)這么早退出呢?由我們第一節(jié)中關(guān)于GUI_ExecDialogBox所做的幾件中可以分析到,當(dāng)UCGUI中有一個(gè)獨(dú)立的窗體退出后_cb會(huì)被清為0,此時(shí)退出GUI窗口LOOP.即結(jié)束了UCGUI窗口消息處理。其實(shí),GUI_MessageBox彈出的消息框其實(shí)也是一種對話框,這最終調(diào)用的還是GUI_ExecDialogBox,開始我們就分析過,進(jìn)入這個(gè)函數(shù)后,會(huì)有一個(gè)全局變量記錄當(dāng)前對話框窗體的消息處理函數(shù)指針,但是目前的問
26、題如下:已經(jīng)建立了兩個(gè)這樣的對話框窗體,這樣一個(gè)全局變量來記載當(dāng)前對話框的窗體消息處理函數(shù)指針顯然不夠,而且先前打開的對話框的的用戶指定的窗體消息回調(diào)函數(shù)已經(jīng)不再被調(diào)用了,此時(shí)第一個(gè)對話框的由子窗體回傳到父窗體的消息均會(huì)傳到第二次打開的對話框的用戶指定的窗體消息回調(diào)函數(shù)中.第二次彈出消息框再次進(jìn)入GUI_ExecDialogBox中的while循環(huán)后,先前的對話框中的while循環(huán)就被掛起了,直至第二次的GUI_ExecDialogBox中的while循環(huán)退出,無論關(guān)閉消息框還是對話框,都會(huì)導(dǎo)致知退出第二次消息LOOP。第二次消息LOOP退出后返回點(diǎn)為彈出消息框后的下一句,直至返回到第一個(gè)對話
27、框的while循環(huán)后退出GUI_ExecDialogBox.但我們期待的結(jié)果是,點(diǎn)擊對話框的OK彈出消息框,關(guān)閉掉對話框或是消息框,其它的都要對話框繼續(xù)有反應(yīng),下面我們就來分析一下如何達(dá)到這個(gè)目標(biāo),看看要做些什么具體的改動(dòng):三、UCGUI中的消息LOOP處理分析-尋找問題的解決辦法.在我們發(fā)現(xiàn)這個(gè)問題,我們已經(jīng)粗步分析了,問題不是出在我們編寫程序上,而是UCGUI的內(nèi)部,那么要解決這個(gè)問題,我們就要進(jìn)一步了解UCGUI的窗口體系。其實(shí)換一句話說,在嵌入式應(yīng)用中,窗口的強(qiáng)大直接決定到GUI系統(tǒng)的體積大小,并不是所有的情況都要有這種支持,當(dāng)然我們希望在下一版本可以有多個(gè)對話框的直接支持。創(chuàng)建對話框
28、:voidMainTask(void)GUI_Init();WM_SetDesktopColor(GUI_RED);WM_SetCreateFlags(WM_CF_MEMDEV);GUI_ExecDialogBox(_aDialogCreate,GUI_COUNTOF(_aDialogCreate),&_cbCallback,0,0,0);上面是我們創(chuàng)建對話框的程序,是我們編寫的代碼,GUI_ExecDialogBox()這個(gè)函數(shù)的作用我們已經(jīng)分析過了,它所做的事用一句話來說就是創(chuàng)建對話框并進(jìn)入窗體消息LOOP處理,下面將詳細(xì)分析一下LOOP消息的處理流程:intGUI_ExecDialogB
29、ox(constGUI_WIDGET_CREATE_INFO*paWidget,intNumWidgets,WM_CALLBACK*cb,WM_HWINhParent,intx0,inty0)_cb=cb;GUI_CreateDialogBox(paWidget,NumWidgets,_cbDialog,hParent,x0,y0);while(_cb)if(!GUI_Exec()GUI_X_ExecIdle();return_r;這個(gè)LOOP類似我們非常熟悉的WIN下面的消息LOOP,其原理是一致的.GUI_CreateDialogBox負(fù)責(zé)創(chuàng)建對話框的所有子窗體,特別注意它其中一個(gè)參數(shù)傳入
30、是Dialog.c中定義的_cbDialog,這個(gè)函數(shù)什么也沒做,基本上是轉(zhuǎn)而調(diào)用_cb,后面我們會(huì)提到關(guān)于它的修改。_cb是對話框的用戶定義窗口消息處理函數(shù),這里面有一個(gè)判斷,就是_cb非空時(shí),才進(jìn)行消息LOOP,_cb在Dialog.c中的定義為:staticWM_CALLBACK*_cb;_cb是一個(gè)全局變量,我們程序中創(chuàng)建對話框與彈出消息框時(shí)兩次調(diào)用了GUI_ExecDialogBox,后一次的_cb將會(huì)把前面的值沖,它是用戶自定義的窗口消息處理函數(shù)。在while中有判斷,那么可見_cb是在GUI_Exec之中是有使用的,對話框的FrameWin子窗體消息流轉(zhuǎn)調(diào)如下面的所示,窗口消息處
31、理函數(shù)是在WM_SendMessage中通過函數(shù)指針的調(diào)用中,注意內(nèi)部的就是真正被調(diào)用來處理消息的函數(shù):GUI_Exec-GUI_Exec1-WM_Exec-WM_Exec1-WM_HandlePID-WM_SendMessage-(*pWin-cb)(pMsg)_FRAMEWIN_Callback-_OnTouch()-(*cb)(pMsg)_cbDialog-*_cb)(pMsg)_MESSAGEBOX_cbCallbackWM_HandlePID()-專門處理類似MOUSE的滑動(dòng)操作外設(shè)消息的函數(shù).WM_SendMessage()-基層的發(fā)送消息的函數(shù),即調(diào)用相對應(yīng)的窗體的消息回調(diào)函數(shù)來
32、處理消息.現(xiàn)在講到了窗體消息LOOP,在窗體系統(tǒng)中最根本一點(diǎn)的就是對外部輸入消息的處理,窗體就是靠消息驅(qū)動(dòng)的,其處理代碼如下:intWM_Exec1(void)if(WM_pfPollPID)/*PollPIDifnecessary*/WM_pfPollPID();if(WM_pfHandlePID)if(WM_pfHandlePID()return1;/*Wehavedonesomething.*/if(GUI_PollKeyMsg()return1;/*Wehavedonesomething.*/if(WM_IsActive&WM_NumInvalidWindows)WM_LOCK();_
33、DrawNext();WM_UNLOCK();return1;/*Wehavedonesomething.*/return0;/*Therewasnothingtodo.*/它主要完成如下幾件事:PollPID中Poll個(gè)詞準(zhǔn)確的意思應(yīng)該是統(tǒng)計(jì)/測試的意思,這里是調(diào)用用戶的統(tǒng)計(jì)測試滑動(dòng)操作外設(shè)的一個(gè)接口,用戶可以通過WM_SetpfPollPID()函數(shù)來設(shè)置自己用于統(tǒng)計(jì)/測試滑動(dòng)操作外設(shè)的具體函數(shù)。處理滑動(dòng)操作外設(shè)WM_TOUCH消息,真正的處理是在函數(shù)WM_HandlePID()中處理的,在后面滑動(dòng)外設(shè)消息處理流程時(shí)有詳細(xì)說明,在新版中更細(xì)分此消息為WM_PID_STATE_CHANGED
34、/WM_MOUSEOVER/WM_TOUCH三種消息,其實(shí)在WIN下面類似消息的處理更為復(fù)雜,有移動(dòng)/滾動(dòng)/單擊DOWN及UP左右鍵/雙擊左右鍵等七八種MOUSE消息,而且這些消息又分為窗體體客戶區(qū)與標(biāo)題區(qū)的差別,標(biāo)題區(qū)的都會(huì)在消息上加上NC的前輟,如WM_NCLBUTTONUP標(biāo)題區(qū)單擊彈起消息。從這里我們也可以看到UCGUI中非常簡化的處理,簡單得不能再簡單了,的確是一個(gè)微型的GUI圖形支持系統(tǒng)。按鍵式外設(shè)消息處理,GUI_PollKeyMsg()函數(shù)在發(fā)現(xiàn)有新的按鍵消息產(chǎn)生時(shí)會(huì)調(diào)用WM_OnKey()將消息發(fā)送到當(dāng)前焦點(diǎn)窗體處理,如果一直處于按鍵按下狀態(tài)時(shí)則會(huì)將前按鈕的虛擬碼存在一全部變
35、量中,以供GUI_GetKey()調(diào)用來返回當(dāng)前按下鍵值。UCGUI中有一個(gè)外部的鍵盤接口,外界通過GUI_StoreKeyMsg()發(fā)送鍵盤消息給UCGUI以驅(qū)動(dòng)鍵盤,在我的模擬器當(dāng)中就是將LCD模擬顯示屏窗口的所有鍵盤消息通過GUI_StoreKeyMsg()傳送到UCGUI中以驅(qū)動(dòng)鍵盤消息處理,關(guān)于鍵盤消息的處理UCGUI中也是來一個(gè)處理一個(gè),沒有任何緩沖處理,如果某些按鈕消息處理用時(shí)過長,就會(huì)造成其后的一些按鍵消息丟失。staticint_Key;/記載當(dāng)前按鍵,GUI_GetKey時(shí)返回此值staticint_KeyMsgCnt;/當(dāng)前鍵盤消息數(shù)量staticstructintKey
36、;/鍵盤虛擬碼intPressedCnt;/按鍵次數(shù)_KeyMsg;上面是鍵盤消息結(jié)構(gòu),UCGUI中以一個(gè)全局的_KeyMsg鍵盤變量記載當(dāng)前最新鍵盤消息,當(dāng)前按鍵值用_Key,每產(chǎn)生按下鍵時(shí)用GUI_StoreKey更新一次此值,UCGUI中沒有按鍵彈起消息的處理。檢測是否有無效窗體,如果有無效窗體,則向該無效窗體發(fā)送重畫消息,有一個(gè)全局變量WM_NumInvalidWindows用于記載當(dāng)前無效窗體的數(shù)目,在函數(shù)_DrawNext()中每次重畫一個(gè)無效窗體,查找無效窗體時(shí)是通過遍歷查找的方法,先前說過窗體基本結(jié)構(gòu)中有一個(gè)成員hNextLin記載下一個(gè)窗體,就在是此處用于遍歷所有窗體,找出無
37、效的窗體,發(fā)送WM_PAINT消息給窗體。注意這里每次畫一個(gè)窗體的原因就是為了不影響窗體的消息處理,如果在此處用時(shí)太多,會(huì)嚴(yán)重影響消息處理的反應(yīng)速度。了解了UCGUI中消息處理的具體流程,那么再來分析這個(gè)先前提到的問題:無論是消息框還是對話框哪一個(gè)先被關(guān)掉,都會(huì)掉用GUI_EndDialog,將_cb被清為零,也就意味著消息LOOP到此結(jié)束了,所以后面另外一個(gè)未被關(guān)掉的當(dāng)然不會(huì)再有任何響應(yīng)了!voidGUI_EndDialog(WM_HWINhWin,intr)_cb=NULL;_r=r;/通知WM_Exec等消息LOOP返回WM_DeleteWindow(hWin);/free該窗體結(jié)構(gòu)占用
38、的內(nèi)存現(xiàn)在我們可以得出一個(gè)結(jié)論:UCGUI中對話框的設(shè)計(jì)只支持單窗口的消息處理,如果要多窗口的支持,可以如同示例中一樣,啟用多任務(wù)支持,不然在單任務(wù)下一個(gè)MainTask中只能支持一個(gè)獨(dú)立窗體,但是如果我們只是為了要彈出一個(gè)消息框而啟動(dòng)一個(gè)任務(wù),這未免太不實(shí)際。了解UCGUI后初步修改路分析如下:消息傳送-經(jīng)過詳細(xì)的分析,認(rèn)識(shí)到在消息處理中創(chuàng)建一個(gè)對話框窗體后,必須建立一個(gè)消息LOOP處理,來向UCGUI中的窗口捕捉并傳送外設(shè)的輸入消息,消息的處理實(shí)質(zhì)上是通過WM_SendMessage函數(shù)來調(diào)用相應(yīng)的窗口的消息回調(diào)函數(shù)。消息LOOP-如果創(chuàng)建多個(gè)對話框窗體,則會(huì)進(jìn)入一個(gè)新的消息LOOP處理層
39、而掛起原來的消息LOOP處理,要避免這種情況發(fā)生必須將消息LOOP移到MainTask之外,并在創(chuàng)建完所有對話框之后執(zhí)行消息LOOP處理。消息分發(fā)-用一個(gè)數(shù)組將所有創(chuàng)建對話框的自定義消息回調(diào)函數(shù)存放起來,然后在對話框消息分布處(_cbDialog函數(shù)處)對應(yīng)分發(fā)各個(gè)對話框的消息,要注意和解決的問題是,必須根據(jù)消息所對應(yīng)用窗體來正確分布。刪除窗體-在清除獨(dú)立窗體時(shí),必須將此對話框?qū)?yīng)的用戶自定義的窗體消息回調(diào)函數(shù)清零,并清除該窗體與其它窗體的數(shù)據(jù)關(guān)系及其占用資源,使其退出消息處理。四、對UCGUI源碼做出部分修改以實(shí)現(xiàn)多獨(dú)立窗口支持.在第三節(jié)當(dāng)中,我們通過進(jìn)一步的分析源碼,大致找到了解決問題的辦
40、法,但那只是理論上的指導(dǎo),實(shí)際上的修改其實(shí)還會(huì)帶來其它的很多問題,因?yàn)樵赨CGUI體系中,對其源碼作出改動(dòng),一定都會(huì)影響到其它的地方,現(xiàn)在我們就實(shí)際的源碼修改說明幾點(diǎn)要注意的問題:實(shí)際上這個(gè)問題有兩種決辦法,第一種改動(dòng)很小,只須進(jìn)行很小的幾處改動(dòng),是在之后想到的方法,最先采用的是第二種方法,對Dialog.c進(jìn)行多處比較大的改動(dòng),比較復(fù)雜,但是之所以還在此處列出,其原因是為了讓大家更加清楚的了解UCGUI中的外設(shè)輸入消息處理機(jī)制,只有在了解了第二種方法的基礎(chǔ)上才能更好的理解第一種方法,否則對于第一種方法不能理解透。下面分別描述這兩種修改辦法:第一種辦法:將GUI_ExecDialogBox中的
41、消息LOOP提出到MainTask這個(gè)UCGUI應(yīng)用當(dāng)中,放在所有的對話框創(chuàng)建之后進(jìn)行;并將在它當(dāng)中增加一個(gè)創(chuàng)建對話框個(gè)數(shù)的變量用于統(tǒng)計(jì)當(dāng)前已經(jīng)創(chuàng)建的對話框數(shù)量,在Dialog.c當(dāng)中有一個(gè)現(xiàn)成沒作什么用的全局變量staticint_r;可以改做此用.將GUI_ExecDialogBox中建對話框時(shí)中調(diào)用GUI_CreateDialogBox所傳的窗體消息回調(diào)函數(shù)改成用戶自定義指定的,而非Dialog.c中中默認(rèn)的_cbDialog,這個(gè)函數(shù)的作用就是調(diào)用用戶指定的對話框窗體消息回調(diào)函數(shù),所以可以在創(chuàng)建對話框中直接傳用戶指定的消息回調(diào)函數(shù)。在GUI_EndDialog當(dāng)中相應(yīng)的將當(dāng)前對話框個(gè)數(shù)
42、減少,每關(guān)閉一個(gè)對話框減一.在Dialog.c增加一個(gè)函數(shù)用于返回當(dāng)前已經(jīng)創(chuàng)建的對話框個(gè)數(shù)GUI_ExecDialogNum(),用于判斷是否應(yīng)該繼續(xù)進(jìn)行消息LOOP處理。須要修改的幾個(gè)函數(shù)修改成如下所示:intGUI_ExecDialogBox(constGUI_WIDGET_CREATE_INFO*paWidget,intNumWidgets,WM_CALLBACK*cb,WM_HWINhParent,intx0,inty0)GUI_CreateDialogBox(paWidget,NumWidgets,cb,hParent,x0,y0);return+_r;voidGUI_EndDial
43、og(WM_HWINhWin,intr)_cb=NULL;_r-;WM_DeleteWindow(hWin);intGUI_ExecDialogNum()return_r;voidMainTask(void)GUI_Init();WM_SetDesktopColor(GUI_RED);WM_SetCreateFlags(WM_CF_MEMDEV);GUI_ExecDialogBox(_aDialogCreate,GUI_COUNTOF(_aDialogCreate),&_cbCallback,0,0,0);while(GUI_ExecDialogNum()if(!GUI_Exec()GUI_X
44、_ExecIdle();lUIks第二種辦法:將原來的_cb修改成一個(gè)結(jié)構(gòu)為new_cb的結(jié)構(gòu)數(shù)組,首設(shè)定最多可創(chuàng)建10個(gè)對話框窗體:typedefstructwin_cbWM_CALLBACK*_cb;/用戶自定義消息回調(diào)函數(shù).WM_HWINhwin;/_cb消息函數(shù)對應(yīng)的對話框窗口.WM_HWINhclient;/_cb消息函數(shù)對應(yīng)的對話框FrameWin窗口客戶區(qū).new_cb,*lpnew_cb;/在_cb數(shù)組中當(dāng)前可用元素位置.staticintdialog_pos=0;/最多可創(chuàng)建對話框窗體數(shù)目,其實(shí)可以改成支持無數(shù)個(gè),但這里作簡單處理staticintMAX_DIALOG=10;
45、/檢查是否還有獨(dú)立窗體存在,以決定是否退出消息LOOP.intcheckHasDialog();/獲取當(dāng)前可用于存放對話框的位置索引,創(chuàng)建新對話框時(shí)調(diào)用.intgetDialogIndex(lpnew_cblp_cb);/對話框窗口數(shù)組,創(chuàng)建對話框后,將其相關(guān)信息記載到該數(shù)組當(dāng)中時(shí),其成員/賦值必須注意幾個(gè)問題,在下面具體代碼中說明:staticnew_cb_cb10;/新修改后的創(chuàng)建對話框的函數(shù).intGUI_ExecDialogBox(constGUI_WIDGET_CREATE_INFO*paWidget,intNumWidgets,WM_CALLBACK*cb,WM_HWINhPare
46、nt,intx0,inty0)dialog_pos=getDialogIndex(_cb);if(dialog_pos!=-1)_cbdialog_pos._cb=cb;elsereturn_r;GUI_CreateDialogBox(paWidget,NumWidgets,_cbDialog,hParent,x0,y0);return_r;WM_HWINGUI_CreateDialogBox(constGUI_WIDGET_CREATE_INFO*paWidget,intNumWidgets,WM_CALLBACK*cb,WM_HWINhParent,intx0,inty0)WM_HWINh
47、Dialog=paWidget-pfCreateIndirect(paWidget,hParent,x0,y0,cb);WM_HWINhDialogClient=WM_GetClientWindow(hDialog);/加到GUI_CreateDialogBox中的,其余不變._cbdialog_pos.hwin=hDialog;_cbdialog_pos+.hclient=hDialogClient;.getDialogIndex(_cb)-創(chuàng)建新的對話框窗體前,首先必須在對話框數(shù)組中查找空位置,如果對話框窗體已達(dá)最大數(shù),則不可再創(chuàng)建對話框窗體,這里只做的是簡單處理,沒有用到動(dòng)態(tài)內(nèi)存分配,主
48、要是因?yàn)槭茄菔荆x者自己可以嘗試支持無限創(chuàng)建對話框窗體。_cbdialog_pos._cb=cb-對話框窗口的窗口消息處理函數(shù)必須在GUI_CreateDialogBox調(diào)用之前賦值,因?yàn)樵贕UI_CreateDialogBox中就會(huì)用到這個(gè)窗口消息處理函數(shù)。_cbdialog_pos中的hwin等窗口句柄的處理加到創(chuàng)建對話框函數(shù)當(dāng)中,千萬不要在調(diào)用創(chuàng)建對話框函數(shù)后再根據(jù)返回的對話框句柄來賦這個(gè)值,因?yàn)樵趧?chuàng)建對話框函數(shù)中創(chuàng)建子窗體時(shí)就會(huì)調(diào)用到對話框消息處理函數(shù),如果hwin此時(shí)未初始化,則在_cDialog()中就無法分發(fā)消息,這樣對話框中的子窗體都無法正確顯示的。GUI_ExecDialog
49、Box中的窗口消息LOOP改為放到MainTask中調(diào)用,因?yàn)楫?dāng)我們把窗體都創(chuàng)建了之后,再來執(zhí)行消息LOOP的話,可以避免前面創(chuàng)建獨(dú)立窗體的消息LOOP被后面創(chuàng)建的消息LOOP中斷的作用。如果我們要?jiǎng)?chuàng)建多個(gè)對話框窗體,那么LOOP當(dāng)中要分發(fā)消息的對象也就是多個(gè)窗體而不是其中的一個(gè),所以要從執(zhí)行單個(gè)對話框函數(shù)中拿出,由用戶來寫在圖形應(yīng)用任務(wù)當(dāng)中,如同WIN中主窗體的消息LOOP處理類似。抽出后如下代碼所示:voidMainTask(void)GUI_Init();WM_SetDesktopColor(GUI_RED);WM_SetCreateFlags(WM_CF_MEMDEV);GUI_Exe
50、cDialogBox(_aDialogCreate,GUI_COUNTOF(_aDialogCreate),&_cbCallback,0,0,0);while(checkHasDialog()if(!GUI_Exec()GUI_X_ExecIdle();2、在第三節(jié)中第2點(diǎn)還說到,要分別調(diào)用各個(gè)對話框窗體的用戶自定義的窗口消息函數(shù),必須注意消息的分發(fā),也就根據(jù)消息中的窗體句柄在對應(yīng)的對話框數(shù)組中查找并調(diào)用相應(yīng)窗體的回調(diào)函數(shù),下面我們看一下具體分發(fā)的代碼:staticvoid_cbDialog(WM_MESSAGE*pMsg)charbuf100;inti=0;WM_LOCK();for(i=0
51、;ihWin)if(pMsg-hWin=_cbi.hwin|_cbi.hclient=pMsg-hWin)(*(_cbi._cb)(pMsg);WM_UNLOCK();_cbDialog是在對話框的FRAMEWIN_cbClient中調(diào)用的形式如下:if(cb)pMsg-hWin=hParent;(*cb)(pMsg);每個(gè)獨(dú)立對話框窗體均是這樣,通過其FrameWin子窗體來調(diào)用用戶自定義的窗口消息處理函數(shù),在分發(fā)消息時(shí),其實(shí)只須要根據(jù)消息中的窗體句柄來分發(fā),因?yàn)槲覀儗τ诿總€(gè)對話框,均記載了它的窗體句柄及FrameWin子窗體句柄。所有創(chuàng)建的獨(dú)立窗體的消息均是在_cbDialog中順序進(jìn)行處
52、理的。3、第三節(jié)中所說的第3點(diǎn),獨(dú)立窗體退出的處理:voidGUI_EndDialog(WM_HWINhWin,intr)inti=0;charbuf255;if(!hWin)return;WM_LOCK();if(WM_IsWindow(hWin)for(i=0;iMAX_DIALOG;i+)if(hWin=_cbi.hwin|_cbi.hclient=hWin)_cbi._cb=NULL;_cbi.hwin=0;_cbi.hclient=0;WM_UNLOCK();_r=r;WM_DeleteWindow(hWin);4、關(guān)于類似MOUSE的滑動(dòng)操作外設(shè)消息的處理函數(shù)WM_HandlePI
53、D().消息LOOP中做的最重要的一件事是獲取消息并分發(fā)到相應(yīng)窗體進(jìn)行處理,這當(dāng)中當(dāng)然包括外設(shè)輸入消息的獲取與處理,WM_HandlePID()函數(shù)就是做這種處理的,它在WM_Exec1中調(diào)用。這個(gè)函數(shù)是專門負(fù)責(zé)處理類似MOUSE的滑動(dòng)操作外設(shè)消息,UCGUI中統(tǒng)稱為WM_TOUCH消息,在GUICoreWMTouch.c文件當(dāng)中,當(dāng)你點(diǎn)擊或是在觸摸屏上按下時(shí)均會(huì)產(chǎn)生此消息。它當(dāng)中有兩個(gè)變量:一個(gè)靜態(tài)的舊消息變量;一個(gè)是局部新消息變量。每次均從消息獲取接口GUI_PID_GetState()中取當(dāng)前WM_TOUCH消息,處理時(shí)會(huì)比較新舊消息發(fā)生的屏幕坐標(biāo)的及外設(shè)操作的狀態(tài)(按下與否)以決定是否
54、處理該消息,每次處理完最新消息后就將最新消息更新到舊消息變量上以避免對相同消息的重復(fù)處理,正是基于這一點(diǎn)才會(huì)將對話框內(nèi)的消息LOOP移到MainTask中進(jìn)行。下面將詳細(xì)分析如此處理的原因及不如此處理會(huì)引發(fā)的問題。五、UCGUI中滑動(dòng)外設(shè)輸入消息的處理機(jī)制-外設(shè)輸入消息處理流程及模態(tài)對話框框的實(shí)現(xiàn)原理初步分析.UCGUI中的的外設(shè)輸入消息統(tǒng)一稱為WM_TOUCH,WM_HandlePID()就是專門處理這種消息的,如MOUSE及觸摸屏等滑動(dòng)操作外設(shè)的消息處理,這種滑動(dòng)外設(shè)消息的處理特征為:一是必須傳送消息發(fā)生點(diǎn)的屏幕X/Y坐標(biāo);二是滑動(dòng)外設(shè)按下與否的操作狀態(tài)。WM_TOUCH消息的處理流程如下
55、:1通過GUI_PID_GetState獲取一個(gè)GUI_PID_STATE結(jié)構(gòu)的WM_TOUCH消息,消息的獲取比較簡單,在GUICoreGUI_PID.C文件當(dāng)中處理,這個(gè)文件提供的是Pointerinputdevice指針輸入設(shè)備的輸入消息處理,但我認(rèn)為將看作為滑動(dòng)操作外設(shè)更為貼切些,文件中提供有以下幾個(gè)函數(shù):GUI_PID_Load-設(shè)定處理此類設(shè)備輸入消息的處理函數(shù),這里為WM_HandlePID().GUI_PID_GetState-獲取設(shè)備最新輸入的消息,UCGUI中處理得很簡單,用一個(gè)全局變量保存當(dāng)前最新輸入的消息,返回此全局變量的一個(gè)COPY即可.GUI_PID_StoreSt
56、ate-設(shè)定設(shè)備最新輸入消息,其實(shí)就是設(shè)定一個(gè)全局變量_State的值,這個(gè)函數(shù)通常在設(shè)備消息接收的任務(wù)當(dāng)中調(diào)用,在模擬器中它是在LCD模擬顯示窗口的MOUSE消息中調(diào)用,這里必須說明的一個(gè)問題是,如果UCGUI在處理某些WM_TOUCH消息時(shí)用去時(shí)間過多的話,那么就會(huì)丟失掉部分WM_TOUCH消息,因?yàn)閁CGUI只是用一個(gè)變量來接收消息而沒有消息隊(duì)列或是一個(gè)數(shù)組來緩存未處理的消息,如果使用隊(duì)列那么必然會(huì)使消息處理更加復(fù)雜,所以如果需要在WM_TOUCH消息中處理一個(gè)用時(shí)比較長的操作,那么最好使用一個(gè)新建的任務(wù)來完成該操作,否則在此過程中不能再處理任何外設(shè)的其它的輸入操作,這里與WIN下面是一
57、樣的,不過WIN下面單任務(wù)情況下只是操作不能及時(shí)有反應(yīng),但不會(huì)丟失后面操作所產(chǎn)生的消息,因?yàn)樗邢㈥?duì)列,在此我們也可以看到UCGUI中很多處理機(jī)制一切重簡.GUI_PID_Init-初始化設(shè)備相關(guān),此處函數(shù)為空.2將新獲取的消息與函數(shù)內(nèi)靜態(tài)的舊消息變量進(jìn)行比較,包括該消息發(fā)生點(diǎn)的屏幕坐標(biāo)及外設(shè)操作狀態(tài)(是否按下):滑動(dòng)操作外設(shè)消息結(jié)構(gòu)如下:typedefstructintx,y;/消息發(fā)生點(diǎn)在屏幕中的x/y坐標(biāo).unsignedcharPressed;/滑動(dòng)外設(shè)是否按下.GUI_PID_STATE;3如果支持圖形鼠標(biāo),則根據(jù)新消息屏幕位置設(shè)置當(dāng)前使用的鼠標(biāo)位置,如果此處不進(jìn)行這個(gè)設(shè)置,則在打
58、開MOUSE支持后,MOUSE是無法移動(dòng)的,在觸摸屏當(dāng)中一般不要求畫出圖形鼠標(biāo),一般只有在PS/2鼠標(biāo)設(shè)備時(shí)才必須畫出圖形鼠標(biāo),否則無法進(jìn)行鼠標(biāo)操作。4當(dāng)新舊消息的操作狀態(tài)比較發(fā)生變化時(shí)處理該消息通過將消息中的外設(shè)按下與否的狀態(tài)相或的值是否為1來判斷,為1則表示狀態(tài)改變,否則不發(fā)送此消息到窗體進(jìn)行處理,而是直接更新新消息到舊消息上,這里我說的情況是UCGUI3.24版源碼的處理情況,但是看現(xiàn)在最新的有源碼的3.90源碼當(dāng)中就處理了此種情況下的消息為WM_MOUSEOVER,還有一個(gè)不同就是將操作狀態(tài)的變化即新舊消息中的是否按下不相等時(shí)作為一個(gè)獨(dú)立的消息WM_PID_STATE_CHANGED來
59、發(fā)送,除此之外的消息才處理為WM_TOUCH消息,但是只要真正理解了UCGUI3.24版源碼中消息處理的根本原理,理解新版源碼中的消息處理也是很容易的,其本質(zhì)并未變化,只是將消息分成了三種處理,這樣顯得更加明確。5構(gòu)造WM_TOUCH消息所需用要的數(shù)據(jù),首先要獲取到當(dāng)前焦點(diǎn)窗體句柄,當(dāng)前焦點(diǎn)窗體是用WM_hCapture的全局變量記載,如果為0則調(diào)用函數(shù)WM_Screen2hWin()根據(jù)消息發(fā)生點(diǎn)的屏幕坐標(biāo)來獲取WM_TOUCH消息的對應(yīng)的窗體句柄,注意這個(gè)函數(shù)是根據(jù)窗體數(shù)據(jù)結(jié)構(gòu),從第一個(gè)創(chuàng)建的窗體WM_FirstWin開始來遞歸查找,先查找窗體的第一個(gè)子窗體,然后查找hNext兄弟窗體,要
60、注意理解此函數(shù),其遞歸查找的本質(zhì)就是按照屏幕上的窗體層疊次序,從最上層窗體開始查找,窗體的前后臺(tái)順序是由父子及兄弟關(guān)系決定的,即UCGUI窗體層疊規(guī)則為:窗體顯示在其下一個(gè)兄弟窗體hNext之前,父窗體顯示在子窗體之后;調(diào)整窗體的前后臺(tái)順序其實(shí)就是調(diào)整窗體在兄弟窗體間的位置,注意這里要遞歸的理解這句話。6比較新舊焦點(diǎn)窗體變量,初始舊焦點(diǎn)窗體變量值為0,每當(dāng)處理消息后,如果是按下狀態(tài)的WM_TOUCH消息,則會(huì)將當(dāng)前焦點(diǎn)窗體句柄更新到舊焦點(diǎn)窗體變量中保存;如果不是按下狀態(tài)的WM_TOUCH消息,則會(huì)在處理完消息后將舊焦點(diǎn)窗體變量賦為0值。這樣處理的原因如下:當(dāng)操作外設(shè)沒有處于按下狀態(tài),此時(shí)進(jìn)行滑
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 26《好的故事》說課稿-2024-2025學(xué)年語文六年級上冊統(tǒng)編版
- 1場景歌說課稿-2024-2025學(xué)年統(tǒng)編版語文二年級上冊
- 2024年秋一年級道德與法治下冊 第二單元 我和大自然 5 風(fēng)兒輕輕吹說課稿 新人教版
- 18古詩三首浪淘沙(其一)說課稿-2024-2025學(xué)年六年級上冊語文統(tǒng)編版
- 8 設(shè)計(jì)制作小車(二) 說課稿-2024-2025學(xué)年科學(xué)四年級上冊教科版
- 23《月光曲》說課稿-2024-2025學(xué)年語文六年級上冊統(tǒng)編版
- 1 24時(shí)計(jì)時(shí)法(說課稿)-2024-2025學(xué)年三年級上冊數(shù)學(xué)人教版001
- 2023九年級道德與法治上冊 第三單元 文明與家園 第五課 守望精神家園第2框 凝聚價(jià)值追求說課稿 新人教版
- 2025北京市飼料采購合同新
- 2025建造船舶所要用到的合同
- 農(nóng)產(chǎn)品貯運(yùn)與加工考試題(附答案)
- 學(xué)校財(cái)務(wù)年終工作總結(jié)4
- 2025年人民教育出版社有限公司招聘筆試參考題庫含答案解析
- 康復(fù)醫(yī)學(xué)治療技術(shù)(士)復(fù)習(xí)題及答案
- 《血管性血友病》課件
- 2025年汽車加氣站作業(yè)人員安全全國考試題庫(含答案)
- 2024年司法考試完整真題及答案
- 高三日語一輪復(fù)習(xí)日語助詞「に」和「を」的全部用法課件
- 2024年山東省高考政治試卷真題(含答案逐題解析)
- 2024年執(zhí)業(yè)藥師繼續(xù)教育專業(yè)答案
- 2024-2025學(xué)年人教版七年級數(shù)學(xué)上冊期末達(dá)標(biāo)測試卷(含答案)
評論
0/150
提交評論