UCGUI窗體管理及消息處理機制分析講課講稿_第1頁
UCGUI窗體管理及消息處理機制分析講課講稿_第2頁
UCGUI窗體管理及消息處理機制分析講課講稿_第3頁
UCGUI窗體管理及消息處理機制分析講課講稿_第4頁
UCGUI窗體管理及消息處理機制分析講課講稿_第5頁
已閱讀5頁,還剩45頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領

文檔簡介

1、Good is good, but better carries it.精益求精,善益求善。UCGUI窗體管理及消息處理機制分析-UCGUI窗體管理及消息處理機制分析-多對話框/模態(tài)窗體/透明窗體支持分析作者:ucgui日期:2005-09-08v2005-06-30完成來源:版本:v版本修改說明時間v實現(xiàn)UCGUI中多對話框支持。2005-06-30v增加UCGUI中各種基本消息介紹。增加窗體消息LOOP機制介紹。增加對話框結(jié)構說明及其消息LOOP處理移到MainTask函數(shù)中由用戶處理的原因剖析,并詳細分析了對話框中按鈕的點擊消息傳送到用戶自定義對話框回調(diào)函數(shù)中處理的傳遞流程。增加外部輸入

2、設備消息處理機制介紹。如滑動操作外設MOUSE及觸摸屏輸入消息(WM_TOUCH)的處理機制,及按鍵式操作外設消息(WM_KEY)處理機制。增加一種更簡單的多對話框支持的方法及說明。增加模態(tài)對話框?qū)崿F(xiàn)原理分析。增加透明窗體實現(xiàn)原理分析。2005-09-08問題的提出:求助關于對話框處理程序中,想在OK按鈕按下后想彈出一個消息框,該怎么做?直接加在程序中好像不行,如何讓消息框彈出后成為模態(tài)窗體呢?請版主幫幫忙。解析在UCGUI中,對話框只支持單個對話框窗體,不支持多個獨立的對話框,現(xiàn)在我們從其源碼來分析一下它為什么支持單個對話框窗體以及如何改進它以支持多個獨立對話框,要講解這個問題我們必須首先理

3、解UCGUI中的窗體消息LOOP,沒有消息LOOP窗體就是死水一潭,不能接受任何外界的輸入,只是一個畫在那里的圖畫而已。聲明本文中提到的源碼均為UCGUI3.24版源碼,新版UCGUI源碼會有改動,請下載本文示例代碼來結(jié)合閱讀本文。摘要:本文主要介紹了UCGUI中的對話框的消息處理機制,并指出在現(xiàn)有UCGUI上如何增加多窗體支持,并在分析解決問題時著重介紹了其輸入設備消息WM_TOUTCH及WM_KEY兩類消息處理方法,并同時初步指出一種在UCGUI中實現(xiàn)模態(tài)對話框以及透明窗體的原理說明,不還有窗體重畫消息WM_PAINT消息處理原理。一、各種基本消息介紹及處理流程-對話框內(nèi)部消息流轉(zhuǎn)及外部消

4、息LOOP分析.UCGUI是采用的消息驅(qū)動的,它專門有對外的一套收集消息的接口,我在模似器中,就是通過LCD模擬顯示屏窗口的MOUSE消息,將MOUSE消息傳入到這個接口中,以驅(qū)動UCGUI中的窗體的。UCGUI中的消息驅(qū)動其實與WINDOWS的是類似的,幾種基本的消息與WINDOWS是一樣的,但UCGUI的更簡單且消息更少,對于一些消息的處理得也很簡化,沒有WINDOWS那么多的消息種類及復雜處理。在WINDOWS中,如我們處理按鈕控件的點擊事件的是在WM_COMMAND消息中,通過按鈕的標志ID來區(qū)分不同的按鈕,所以按鈕標志ID必須不同的,否則無法區(qū)別開(除非不在父窗體的WM_COMMAN

5、D消息中處理)。UCGUI中一些基本的消息如下:WM_CREATE-窗體創(chuàng)建消息,每創(chuàng)建一個窗體完后都會向該窗體發(fā)送此消息,如WM_CreateWindowAsChild創(chuàng)建完窗體均會發(fā)一此消息,但在UCGUI中對于此消息的很少處理,如果用戶想在對話框之后做些初始化操作或是創(chuàng)建其它子窗體的動作,可以處理此消息,不過對話框一般有專門的初始化消息WM_INIT_DIALOG,它是在創(chuàng)建對話框后發(fā)送的。WM_SHOW-顯示窗體消息,此消息在UCGUI中各控件窗體內(nèi)均未作處理,如果你通過消息發(fā)送函數(shù)來發(fā)送這類沒有在UCGUI中各窗體中處理的消息,是沒有有什么響應的,不要感到奇怪。要顯示窗體一般是通過W

6、M_ShowWindow()函數(shù)實現(xiàn)的,這個函數(shù)做的也就是改變窗體顯示標志W(wǎng)M_SF_ISVIS,并使窗體矩形區(qū)域無效WM_InvalidateWindow()以產(chǎn)生重畫消息。WM_SET_ENABLE-設置窗體不能使用消息,UCGUI中有一種復選框為不可改變的,但是這個功能也不完全,如果你對著UCGUI中的按鈕使用WM_DisableWindow()來設置其無效,按鈕照樣還是可以使用,不過要改進這些小毛病還是很容易的,這里只是提醒大家UCGUI中很多沒有實現(xiàn)的小地方,不要到時候使用時感到很奇怪,感覺到奇怪時最好去看看源碼,看看源碼中是否實現(xiàn)了此功能,不要郁悶。WM_PAINT-窗體重畫消息,

7、當窗體所在區(qū)域全部或是部分區(qū)域無效時,系統(tǒng)將會發(fā)出該重畫消息,將無效區(qū)域重畫,但UCGUI中的處理比較簡單,都是將窗體全部區(qū)域重畫;如果用戶自己想在窗體上畫上一些信息,一般都在在該消息當中畫,UCGUI中的各種提供的系統(tǒng)控件都必須在其系統(tǒng)的提供的消息回調(diào)函數(shù)中處理此消息來畫出控件。當由外部輸入操作引起無效窗體區(qū)域產(chǎn)生時,系統(tǒng)都會在消息處理中發(fā)送該消息到窗體消息回調(diào)函數(shù)中,以重畫此窗體,在下面講解消息循環(huán)機制時將會著重講解到該消息的產(chǎn)生。透明窗體-經(jīng)常有朋友想知道在UCGUI中如何實現(xiàn)透明窗體,透明窗窗體顯示在前臺時,可以看到部分位于其窗體后的內(nèi)容,即透過窗體可以看到窗體背后的圖象。在UCGUI

8、中有關于透明窗體的設置選項,可是沒有實現(xiàn)此功能,其實要實現(xiàn)原理如下:第一透明窗體及其所有子窗體都必須透明處理;第二是對于所有有透明屬性的窗體,在繪圖時必須使用透明填充功能的矩形填充函數(shù),主要是修改窗體的WM_PAINT消息中畫窗體時的矩形填充函數(shù)為透明的矩形填充;第三透明的矩形填充函數(shù)的實現(xiàn),通常情況下的矩形填充是以當前前景色來填充,那么關鍵就是實現(xiàn)畫點函數(shù)的透明填充,要使一個透明,可以取當前顯存中存點的點的RGB顏色,然后再與當前要畫的顏色按照一個比例進行混合得一個新的RGB值,再將此值畫以屏幕上就可能實現(xiàn)透明填充的效果。WM_TOUCH-處理類似MOUSE的滑動操作方式的輸入外設的消息,如

9、觸摸屏一般都是將其消息從硬件接收到后轉(zhuǎn)化為該消息形式發(fā)送出去,該消息中必須包含消息在屏幕中的發(fā)生位置坐標及輸入設備狀態(tài)(按下狀態(tài)或彈起狀態(tài)),此消息在任務消息循環(huán)中循環(huán)處理,一旦產(chǎn)生就會發(fā)送給當前焦點窗體,在后面將詳細講解該消息的處理機制。WM_KEY-處理類似KEY的按鍵式操作的輸入外設的消息,消息中必須包含按鍵的按下或彈起狀態(tài),此消息也是在任務消息循環(huán)中循環(huán)處理,一旦產(chǎn)生就會發(fā)送給當前焦點窗體,講解消息LOOP時再詳細介紹。WM_SET_FOCUS-講到剛才上面的兩個消息時,就反復提到了當前焦點窗體的概念,所有外部輸入設備消息都是發(fā)送給當前焦點窗體的,用戶可以通過此消息來設定當前的焦點窗體

10、。外部輸入操作也會改變當前焦點窗體,如點擊某窗體時會在該窗體的WM_TOUCH消息處理中設置該窗體本身為當前焦點窗體;當在對話框中按鍵TAB鍵時,同樣也可以將焦點在對話框上各控件間切換,這是在對話框的WM_KEY消息中處理實現(xiàn)的了解一下WM_SetFocusOnNextChild()函數(shù),是根據(jù)創(chuàng)建對話框時指定的資源定義數(shù)組中的順序來切換的,并沒有WIN下面指定的TabIndex這樣一個值來指定次序的值。WM_NOTIFY_PARENT-這個消息將子窗體的外設輸入的消息傳送到它的父窗體,因為一般的情況下消息都是在父窗體中統(tǒng)一處理的,如對話框中的按鈕點擊事件,一般都是在用戶自定義的窗體消息處理函

11、數(shù)中處理,所以就必須要子窗體將獲取的輸入外設的消息傳送給父窗體,這樣才能在父窗體中進行子窗體的點擊事件消息的處理,這個消息的機制類似WIN下面的WM_COMMAND消息,處理該消息時通過控件ID來區(qū)別不同的控件,通過消息中的通知碼來區(qū)別控件被操作的各種狀態(tài),具體這個消息的詳細說明請參見后面的分析。WM_DELETE-要刪除窗體時發(fā)送的消息,主要清除窗體數(shù)據(jù)結(jié)構所占用內(nèi)存,此消息主要由WM_DeleteWindow()函數(shù)發(fā)送了,如點擊OK按鈕關閉對話框時,最終會調(diào)用此函數(shù)來刪除窗體,不過UCGUI中沒有最大化最小化關閉等系統(tǒng)功能按鈕。最基礎窗體結(jié)構注解如下,在該結(jié)構中有兩個很重要的成員,hNe

12、xtLin是記載窗體的下一個窗體,這個成員用于遍歷所有已經(jīng)創(chuàng)建的窗體;hNext是記載窗體下一個兄弟窗體,這個成員用于遍歷每個窗體對應的子窗體;這個結(jié)構是最基礎,一般的控件在這個結(jié)構之上還會有一些擴展的結(jié)構,如按鈕對應有BUTTON_Obj結(jié)構。typedefstructWM_OBJ_structWM_Obj;structWM_OBJ_structGUI_RECTRect;/*窗體矩形區(qū)域*/GUI_RECTInvalidRect;/*窗體無效矩形區(qū)域*/WM_CALLBACK*cb;/*窗體消息回調(diào)函數(shù)*/WM_HWINhNextLin;/*窗體下一個窗體句柄*/WM_HWINhParent

13、;/*父窗體句柄*/WM_HWINhFirstChild;/*第一子窗體句柄*/WM_HWINhNext;/*下一個兄弟窗體句柄*/U16Status;/*窗體當前狀態(tài)*/;WIDGET_HandleActive()基礎控件共通消息處理,在大部分的UCGUI控件中都會在消息回調(diào)函數(shù)的頭部進行這個調(diào)用,如果處理了消息后,就直接退出消息回調(diào)函數(shù)的調(diào)用。這個函數(shù)中處理如下消息:WM_GET_ID返窗體控件標志ID.WM_SET_FOCUS設置當前窗體為焦點窗體,設置完后還必須向該窗體的父窗體發(fā)送一個WM_NOTIFY_CHILD_HAS_FOCUS消息讓其父窗體更新它記載的當前焦點子窗體.WM_GE

14、T_HAS_FOCUS獲取當前窗體是否為焦點窗體.WM_SET_ENABLE設置窗體為不可用窗體.WM_GET_ACCEPT_FOCUS獲取當前窗體是否可設置為焦點窗體.WM_GET_INSIDE_RECT返回窗體內(nèi)框矩形,如按鈕有3D效果時會有效果邊框?qū)挾?,?nèi)框矩形就是窗體矩形被邊框剪裁后的矩形.WM_DefaultProc()-窗體默認消息處理函數(shù),UCGUI中提供一些基礎的控件,這些控件有些共通的消息均在此處理,如下:WM_GETCLIENTRECT獲取窗體矩形區(qū)域,相對于矩形自身WM_GETORG獲取窗體矩形左上角坐標.WM_GET_INSIDE_RECT獲取窗體矩形區(qū)域,相對屏幕.W

15、M_GET_CLIENT_WINDOW獲取窗體客戶區(qū)子窗體句柄,如對話框的中的子窗體FrameWin即為此種窗體.WM_KEY銨鍵消息處理,通知父窗體子窗體的按鍵消息,有些控件自己要處理這個消息,如Edit控件處理完此消息后就沒有再調(diào)用WM_DefaultProc(),從而沒有將WM_KEY消息通父窗體;如Button控件,根本沒有對此消息進行處理,直接是通過默認處理發(fā)給了父窗體處理;有些控件如Checkbox自己處理該消息,同時也調(diào)用默認消息處量將此消息通知父窗本,此種消息源窗體為子控件,目標窗體為父窗體。如此處理WM_KEY消息完全是UCGUI中如此做,在WIN中并沒有這樣做.WM_GET

16、_BKCOLOR獲取窗體背景色,在此未實現(xiàn),返回0 xfffffff值,但FrameWin窗體實現(xiàn)了此消息處理.在UCGUI的對話框的窗口消息處理函數(shù)中OK按鈕的點擊事件,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這個消息是由子窗體傳送給父窗體的,由消息的名字也可以看出這一點,OK按鈕也

18、是一個窗體,當MOUSE點擊在它上面時,UCGUI首先會傳遞一個WM_TOUCH消息到OK按鈕的窗口消息處理函數(shù),OK按鈕是一個系統(tǒng)提供的控件,系統(tǒng)已經(jīng)提供了一個默認的消息的窗口消息處理函數(shù),這個函數(shù)會處理大部分的默認窗口消息并隨后將此消息轉(zhuǎn)發(fā)給父窗體,即WM_NOTIFY_PARENT消息,它是由函數(shù)WM_NotifyParent(hObj,Notification)實現(xiàn)的.WM_TOUCH消息在按鈕的消息處理函數(shù)_BUTTON_Callback中的_OnTouch函數(shù)中處理,在處理過程完后會調(diào)用WM_NotifyParent向按鈕的父窗體發(fā)WM_NOTIFY_PARENT消息告訴對話框回調(diào)

19、函數(shù)按鈕被點擊了,這個過程再說詳細一點是這樣的:點擊OK按鈕.產(chǎn)生按鈕WM_TOUCH消息.UCGUI中的消息LOOP調(diào)用按鈕默認的按鈕窗口消息處理函數(shù)_BUTTON_Callback._OnTouch默認處理按鈕點擊并發(fā)送給父窗體WM_NOTIFY_PARENT消息,這里要注意MOUSE點擊后,有三種情況:第一種是點擊后在按鈕范圍內(nèi)彈出MOUSE,這種情況下,會送的消息中還有一個通知碼就是WM_NOTIFICATION_RELEASED;第二種情況是點擊拖到按鈕范圍外彈起MOUSE,此時通知碼是WM_NOTIFICATION_MOVED_OUT;第三種情況是點擊后一直未彈起MOUSE的過程中

20、消息通知碼為WM_NOTIFICATION_CLICKED;在這個函數(shù)中還會處理設置按鈕點擊后MOUSE至未彈起前的按下狀態(tài),這樣在按鈕下一次畫出時就會以按下的狀態(tài)顯示出來.默認的對話框窗體消息處理函數(shù)_FRAMEWIN_Callback收到WM_NOTIFY_PARENT消息并最終傳送該消息到用戶自己定義的對話框消息處理函數(shù),這里要注意的一點是,其實對話框主要是由一個FrameWin子窗體構成的,這個子窗體大小為對話框指定的大小,對話框上的其它控件是都是FrameWin的子窗體,由_FRAMEWIN_Callback傳送的消息首先是傳送到對話框的默認窗體消息回調(diào)函數(shù)_cbDialog,然后再

21、經(jīng)它傳送到用戶自定義的窗體回調(diào)函數(shù)當中。用戶在自己的對話框消息處理函數(shù)中處理WM_NOTIFY_PARENT消息,即按鈕的點擊消息,該消息參數(shù)中含有按鈕的ID及操作狀態(tài),如果通知碼是WM_NOTIFICATION_RELEASED,此時證明一次點擊事件完成。voidWM_NotifyParent(WM_HWINhWin,intNotification)WM_MESSAGEMsg;Msg.MsgId=WM_NOTIFY_PARENT;Msg.Data.v=Notification;WM_SendToParent(hWin,&Msg);這個函數(shù)相當簡單,其主要還是WM_SendToParent這個

22、函數(shù)的調(diào)用,這個函數(shù)再調(diào)用voidWM_SendMessage(WM_HWINhWin,WM_MESSAGE*pMsg),這個函數(shù)是最基本的一個消息發(fā)送處理函數(shù),它的第一個參數(shù)指定了接受這個要處理的消息的句柄,第二個指定了是什么消息。這個函數(shù)的主要作用是調(diào)用相應窗口的消息處理函數(shù)來處理消息,如果你有消息要發(fā)送給指定的窗體處理,那么也可以使用這個函數(shù)。在上面,我們剛剛分析了在對話框內(nèi)部消息處理的流轉(zhuǎn),其中分析了我們在自己指定的對話框消息處理函數(shù)當中是如何可以獲得按鈕的點擊消息并進行處理的,現(xiàn)在我們就再來分析一下對話框外面的消息接收:首先是來了解一下GUI_ExecDialogBox函數(shù),這個函數(shù)

23、有幾個參數(shù):第一個是對話框的資源定義數(shù)組,這個數(shù)組定義了對話框的組成子窗體,其中數(shù)組第一個成員必須是FrameWin窗體,數(shù)組每一個成員記載了創(chuàng)建子窗體所用函數(shù)/子窗體Caption/子窗體標志ID/子窗體的位置及寬高/創(chuàng)建窗體時樣式標志/額外傳送的參數(shù).第二個參數(shù)是上述的數(shù)組的大小.第三個參數(shù)是用戶指定的對話框窗體消息回調(diào)函數(shù)指針.第四個參數(shù)是對話框的父窗體,默認為0.第五、六參數(shù)指定對話框的左上角屏幕位置.GUI_ExecDialogBox主要完成如下幾件事:根據(jù)傳進來的對話框資源定義數(shù)組創(chuàng)建對話框及對話框中的子窗體.根據(jù)傳進來的窗口消息處理函數(shù),記載到一全局變量保存,當這個全局變量中記載

24、的函數(shù)指針為非空時,執(zhí)行消息LOOP,消息LOOP中會將當前的MOUSE及KEY消息發(fā)送給當前焦點窗體.當對話框關閉時,記載對話窗體消息回調(diào)函數(shù)的全局變量會被清為0,此時消息LOOP就會退出,對話框結(jié)束.二、發(fā)現(xiàn)存在的問題-點擊OK后無論先關閉消息框還是對話框,另一個不再響應.點擊對話框的OK后彈出消息框,會出現(xiàn)當按下對話框的Cancel關閉對話框后,彈出的消息框就沒有任何響應的情況.或者是關閉掉彈出的消息框,對話框就沒有任何響應的情形:從外部粗步分析的原因是調(diào)用MainTask的線程已經(jīng)退出了,這個線程是在模擬器中開啟的專門用于運行GUI任務的線程,它的線程函數(shù)是Thread,Thread函

25、數(shù)里調(diào)用main,main中再調(diào)用MainTask,所以該線程退出后也就代表UCGUI任務已經(jīng)結(jié)束了。這是從模擬器的角度來分析,現(xiàn)在我們分析一下為什么MainTask的調(diào)用線程會這么早退出呢?由我們第一節(jié)中關于GUI_ExecDialogBox所做的幾件中可以分析到,當UCGUI中有一個獨立的窗體退出后_cb會被清為0,此時退出GUI窗口LOOP.即結(jié)束了UCGUI窗口消息處理。其實,GUI_MessageBox彈出的消息框其實也是一種對話框,這最終調(diào)用的還是GUI_ExecDialogBox,開始我們就分析過,進入這個函數(shù)后,會有一個全局變量記錄當前對話框窗體的消息處理函數(shù)指針,但是目前的問

26、題如下:已經(jīng)建立了兩個這樣的對話框窗體,這樣一個全局變量來記載當前對話框的窗體消息處理函數(shù)指針顯然不夠,而且先前打開的對話框的的用戶指定的窗體消息回調(diào)函數(shù)已經(jīng)不再被調(diào)用了,此時第一個對話框的由子窗體回傳到父窗體的消息均會傳到第二次打開的對話框的用戶指定的窗體消息回調(diào)函數(shù)中.第二次彈出消息框再次進入GUI_ExecDialogBox中的while循環(huán)后,先前的對話框中的while循環(huán)就被掛起了,直至第二次的GUI_ExecDialogBox中的while循環(huán)退出,無論關閉消息框還是對話框,都會導致知退出第二次消息LOOP。第二次消息LOOP退出后返回點為彈出消息框后的下一句,直至返回到第一個對話

27、框的while循環(huán)后退出GUI_ExecDialogBox.但我們期待的結(jié)果是,點擊對話框的OK彈出消息框,關閉掉對話框或是消息框,其它的都要對話框繼續(xù)有反應,下面我們就來分析一下如何達到這個目標,看看要做些什么具體的改動:三、UCGUI中的消息LOOP處理分析-尋找問題的解決辦法.在我們發(fā)現(xiàn)這個問題,我們已經(jīng)粗步分析了,問題不是出在我們編寫程序上,而是UCGUI的內(nèi)部,那么要解決這個問題,我們就要進一步了解UCGUI的窗口體系。其實換一句話說,在嵌入式應用中,窗口的強大直接決定到GUI系統(tǒng)的體積大小,并不是所有的情況都要有這種支持,當然我們希望在下一版本可以有多個對話框的直接支持。創(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()這個函數(shù)的作用我們已經(jīng)分析過了,它所做的事用一句話來說就是創(chuàng)建對話框并進入窗體消息LOOP處理,下面將詳細分析一下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;這個LOOP類似我們非常熟悉的WIN下面的消息LOOP,其原理是一致的.GUI_CreateDialogBox負責創(chuàng)建對話框的所有子窗體,特別注意它其中一個參數(shù)傳入

30、是Dialog.c中定義的_cbDialog,這個函數(shù)什么也沒做,基本上是轉(zhuǎn)而調(diào)用_cb,后面我們會提到關于它的修改。_cb是對話框的用戶定義窗口消息處理函數(shù),這里面有一個判斷,就是_cb非空時,才進行消息LOOP,_cb在Dialog.c中的定義為:staticWM_CALLBACK*_cb;_cb是一個全局變量,我們程序中創(chuàng)建對話框與彈出消息框時兩次調(diào)用了GUI_ExecDialogBox,后一次的_cb將會把前面的值沖,它是用戶自定義的窗口消息處理函數(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的滑動操作外設消息的函數(shù).WM_SendMessage()-基層的發(fā)送消息的函數(shù),即調(diào)用相對應的窗體的消息回調(diào)函數(shù)來

32、處理消息.現(xiàn)在講到了窗體消息LOOP,在窗體系統(tǒng)中最根本一點的就是對外部輸入消息的處理,窗體就是靠消息驅(qū)動的,其處理代碼如下: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個詞準確的意思應該是統(tǒng)計/測試的意思,這里是調(diào)用用戶的統(tǒng)計測試滑動操作外設的一個接口,用戶可以通過WM_SetpfPollPID()函數(shù)來設置自己用于統(tǒng)計/測試滑動操作外設的具體函數(shù)。處理滑動操作外設WM_TOUCH消息,真正的處理是在函數(shù)WM_HandlePID()中處理的,在后面滑動外設消息處理流程時有詳細說明,在新版中更細分此消息為WM_PID_STATE_CHANGED

34、/WM_MOUSEOVER/WM_TOUCH三種消息,其實在WIN下面類似消息的處理更為復雜,有移動/滾動/單擊DOWN及UP左右鍵/雙擊左右鍵等七八種MOUSE消息,而且這些消息又分為窗體體客戶區(qū)與標題區(qū)的差別,標題區(qū)的都會在消息上加上NC的前輟,如WM_NCLBUTTONUP標題區(qū)單擊彈起消息。從這里我們也可以看到UCGUI中非常簡化的處理,簡單得不能再簡單了,的確是一個微型的GUI圖形支持系統(tǒng)。按鍵式外設消息處理,GUI_PollKeyMsg()函數(shù)在發(fā)現(xiàn)有新的按鍵消息產(chǎn)生時會調(diào)用WM_OnKey()將消息發(fā)送到當前焦點窗體處理,如果一直處于按鍵按下狀態(tài)時則會將前按鈕的虛擬碼存在一全部變

35、量中,以供GUI_GetKey()調(diào)用來返回當前按下鍵值。UCGUI中有一個外部的鍵盤接口,外界通過GUI_StoreKeyMsg()發(fā)送鍵盤消息給UCGUI以驅(qū)動鍵盤,在我的模擬器當中就是將LCD模擬顯示屏窗口的所有鍵盤消息通過GUI_StoreKeyMsg()傳送到UCGUI中以驅(qū)動鍵盤消息處理,關于鍵盤消息的處理UCGUI中也是來一個處理一個,沒有任何緩沖處理,如果某些按鈕消息處理用時過長,就會造成其后的一些按鍵消息丟失。staticint_Key;/記載當前按鍵,GUI_GetKey時返回此值staticint_KeyMsgCnt;/當前鍵盤消息數(shù)量staticstructintKey

36、;/鍵盤虛擬碼intPressedCnt;/按鍵次數(shù)_KeyMsg;上面是鍵盤消息結(jié)構,UCGUI中以一個全局的_KeyMsg鍵盤變量記載當前最新鍵盤消息,當前按鍵值用_Key,每產(chǎn)生按下鍵時用GUI_StoreKey更新一次此值,UCGUI中沒有按鍵彈起消息的處理。檢測是否有無效窗體,如果有無效窗體,則向該無效窗體發(fā)送重畫消息,有一個全局變量WM_NumInvalidWindows用于記載當前無效窗體的數(shù)目,在函數(shù)_DrawNext()中每次重畫一個無效窗體,查找無效窗體時是通過遍歷查找的方法,先前說過窗體基本結(jié)構中有一個成員hNextLin記載下一個窗體,就在是此處用于遍歷所有窗體,找出無

37、效的窗體,發(fā)送WM_PAINT消息給窗體。注意這里每次畫一個窗體的原因就是為了不影響窗體的消息處理,如果在此處用時太多,會嚴重影響消息處理的反應速度。了解了UCGUI中消息處理的具體流程,那么再來分析這個先前提到的問題:無論是消息框還是對話框哪一個先被關掉,都會掉用GUI_EndDialog,將_cb被清為零,也就意味著消息LOOP到此結(jié)束了,所以后面另外一個未被關掉的當然不會再有任何響應了!voidGUI_EndDialog(WM_HWINhWin,intr)_cb=NULL;_r=r;/通知WM_Exec等消息LOOP返回WM_DeleteWindow(hWin);/free該窗體結(jié)構占用

38、的內(nèi)存現(xiàn)在我們可以得出一個結(jié)論:UCGUI中對話框的設計只支持單窗口的消息處理,如果要多窗口的支持,可以如同示例中一樣,啟用多任務支持,不然在單任務下一個MainTask中只能支持一個獨立窗體,但是如果我們只是為了要彈出一個消息框而啟動一個任務,這未免太不實際。了解UCGUI后初步修改路分析如下:消息傳送-經(jīng)過詳細的分析,認識到在消息處理中創(chuàng)建一個對話框窗體后,必須建立一個消息LOOP處理,來向UCGUI中的窗口捕捉并傳送外設的輸入消息,消息的處理實質(zhì)上是通過WM_SendMessage函數(shù)來調(diào)用相應的窗口的消息回調(diào)函數(shù)。消息LOOP-如果創(chuàng)建多個對話框窗體,則會進入一個新的消息LOOP處理層

39、而掛起原來的消息LOOP處理,要避免這種情況發(fā)生必須將消息LOOP移到MainTask之外,并在創(chuàng)建完所有對話框之后執(zhí)行消息LOOP處理。消息分發(fā)-用一個數(shù)組將所有創(chuàng)建對話框的自定義消息回調(diào)函數(shù)存放起來,然后在對話框消息分布處(_cbDialog函數(shù)處)對應分發(fā)各個對話框的消息,要注意和解決的問題是,必須根據(jù)消息所對應用窗體來正確分布。刪除窗體-在清除獨立窗體時,必須將此對話框?qū)挠脩糇远x的窗體消息回調(diào)函數(shù)清零,并清除該窗體與其它窗體的數(shù)據(jù)關系及其占用資源,使其退出消息處理。四、對UCGUI源碼做出部分修改以實現(xiàn)多獨立窗口支持.在第三節(jié)當中,我們通過進一步的分析源碼,大致找到了解決問題的辦

40、法,但那只是理論上的指導,實際上的修改其實還會帶來其它的很多問題,因為在UCGUI體系中,對其源碼作出改動,一定都會影響到其它的地方,現(xiàn)在我們就實際的源碼修改說明幾點要注意的問題:實際上這個問題有兩種決辦法,第一種改動很小,只須進行很小的幾處改動,是在之后想到的方法,最先采用的是第二種方法,對Dialog.c進行多處比較大的改動,比較復雜,但是之所以還在此處列出,其原因是為了讓大家更加清楚的了解UCGUI中的外設輸入消息處理機制,只有在了解了第二種方法的基礎上才能更好的理解第一種方法,否則對于第一種方法不能理解透。下面分別描述這兩種修改辦法:第一種辦法:將GUI_ExecDialogBox中的

41、消息LOOP提出到MainTask這個UCGUI應用當中,放在所有的對話框創(chuàng)建之后進行;并將在它當中增加一個創(chuàng)建對話框個數(shù)的變量用于統(tǒng)計當前已經(jīng)創(chuàng)建的對話框數(shù)量,在Dialog.c當中有一個現(xiàn)成沒作什么用的全局變量staticint_r;可以改做此用.將GUI_ExecDialogBox中建對話框時中調(diào)用GUI_CreateDialogBox所傳的窗體消息回調(diào)函數(shù)改成用戶自定義指定的,而非Dialog.c中中默認的_cbDialog,這個函數(shù)的作用就是調(diào)用用戶指定的對話框窗體消息回調(diào)函數(shù),所以可以在創(chuàng)建對話框中直接傳用戶指定的消息回調(diào)函數(shù)。在GUI_EndDialog當中相應的將當前對話框個數(shù)

42、減少,每關閉一個對話框減一.在Dialog.c增加一個函數(shù)用于返回當前已經(jīng)創(chuàng)建的對話框個數(shù)GUI_ExecDialogNum(),用于判斷是否應該繼續(xù)進行消息LOOP處理。須要修改的幾個函數(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修改成一個結(jié)構為new_cb的結(jié)構數(shù)組,首設定最多可創(chuàng)建10個對話框窗體:typedefstructwin_cbWM_CALLBACK*_cb;/用戶自定義消息回調(diào)函數(shù).WM_HWINhwin;/_cb消息函數(shù)對應的對話框窗口.WM_HWINhclient;/_cb消息函數(shù)對應的對話框FrameWin窗口客戶區(qū).new_cb,*lpnew_cb;/在_cb數(shù)組中當前可用元素位置.staticintdialog_pos=0;/最多可創(chuàng)建對話框窗體數(shù)目,其實可以改成支持無數(shù)個,但這里作簡單處理staticintMAX_DIALOG=10;

45、/檢查是否還有獨立窗體存在,以決定是否退出消息LOOP.intcheckHasDialog();/獲取當前可用于存放對話框的位置索引,創(chuàng)建新對話框時調(diào)用.intgetDialogIndex(lpnew_cblp_cb);/對話框窗口數(shù)組,創(chuàng)建對話框后,將其相關信息記載到該數(shù)組當中時,其成員/賦值必須注意幾個問題,在下面具體代碼中說明: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ù)組中查找空位置,如果對話框窗體已達最大數(shù),則不可再創(chuàng)建對話框窗體,這里只做的是簡單處理,沒有用到動態(tài)內(nèi)存分配,主

48、要是因為是演示,讀者自己可以嘗試支持無限創(chuàng)建對話框窗體。_cbdialog_pos._cb=cb-對話框窗口的窗口消息處理函數(shù)必須在GUI_CreateDialogBox調(diào)用之前賦值,因為在GUI_CreateDialogBox中就會用到這個窗口消息處理函數(shù)。_cbdialog_pos中的hwin等窗口句柄的處理加到創(chuàng)建對話框函數(shù)當中,千萬不要在調(diào)用創(chuàng)建對話框函數(shù)后再根據(jù)返回的對話框句柄來賦這個值,因為在創(chuàng)建對話框函數(shù)中創(chuàng)建子窗體時就會調(diào)用到對話框消息處理函數(shù),如果hwin此時未初始化,則在_cDialog()中就無法分發(fā)消息,這樣對話框中的子窗體都無法正確顯示的。GUI_ExecDialog

49、Box中的窗口消息LOOP改為放到MainTask中調(diào)用,因為當我們把窗體都創(chuàng)建了之后,再來執(zhí)行消息LOOP的話,可以避免前面創(chuàng)建獨立窗體的消息LOOP被后面創(chuàng)建的消息LOOP中斷的作用。如果我們要創(chuàng)建多個對話框窗體,那么LOOP當中要分發(fā)消息的對象也就是多個窗體而不是其中的一個,所以要從執(zhí)行單個對話框函數(shù)中拿出,由用戶來寫在圖形應用任務當中,如同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ào)用各個對話框窗體的用戶自定義的窗口消息函數(shù),必須注意消息的分發(fā),也就根據(jù)消息中的窗體句柄在對應的對話框數(shù)組中查找并調(diào)用相應窗體的回調(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);每個獨立對話框窗體均是這樣,通過其FrameWin子窗體來調(diào)用用戶自定義的窗口消息處理函數(shù),在分發(fā)消息時,其實只須要根據(jù)消息中的窗體句柄來分發(fā),因為我們對于每個對話框,均記載了它的窗體句柄及FrameWin子窗體句柄。所有創(chuàng)建的獨立窗體的消息均是在_cbDialog中順序進行處

52、理的。3、第三節(jié)中所說的第3點,獨立窗體退出的處理: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、關于類似MOUSE的滑動操作外設消息的處理函數(shù)WM_HandlePI

53、D().消息LOOP中做的最重要的一件事是獲取消息并分發(fā)到相應窗體進行處理,這當中當然包括外設輸入消息的獲取與處理,WM_HandlePID()函數(shù)就是做這種處理的,它在WM_Exec1中調(diào)用。這個函數(shù)是專門負責處理類似MOUSE的滑動操作外設消息,UCGUI中統(tǒng)稱為WM_TOUCH消息,在GUICoreWMTouch.c文件當中,當你點擊或是在觸摸屏上按下時均會產(chǎn)生此消息。它當中有兩個變量:一個靜態(tài)的舊消息變量;一個是局部新消息變量。每次均從消息獲取接口GUI_PID_GetState()中取當前WM_TOUCH消息,處理時會比較新舊消息發(fā)生的屏幕坐標的及外設操作的狀態(tài)(按下與否)以決定是否

54、處理該消息,每次處理完最新消息后就將最新消息更新到舊消息變量上以避免對相同消息的重復處理,正是基于這一點才會將對話框內(nèi)的消息LOOP移到MainTask中進行。下面將詳細分析如此處理的原因及不如此處理會引發(fā)的問題。五、UCGUI中滑動外設輸入消息的處理機制-外設輸入消息處理流程及模態(tài)對話框框的實現(xiàn)原理初步分析.UCGUI中的的外設輸入消息統(tǒng)一稱為WM_TOUCH,WM_HandlePID()就是專門處理這種消息的,如MOUSE及觸摸屏等滑動操作外設的消息處理,這種滑動外設消息的處理特征為:一是必須傳送消息發(fā)生點的屏幕X/Y坐標;二是滑動外設按下與否的操作狀態(tài)。WM_TOUCH消息的處理流程如下

55、:1通過GUI_PID_GetState獲取一個GUI_PID_STATE結(jié)構的WM_TOUCH消息,消息的獲取比較簡單,在GUICoreGUI_PID.C文件當中處理,這個文件提供的是Pointerinputdevice指針輸入設備的輸入消息處理,但我認為將看作為滑動操作外設更為貼切些,文件中提供有以下幾個函數(shù):GUI_PID_Load-設定處理此類設備輸入消息的處理函數(shù),這里為WM_HandlePID().GUI_PID_GetState-獲取設備最新輸入的消息,UCGUI中處理得很簡單,用一個全局變量保存當前最新輸入的消息,返回此全局變量的一個COPY即可.GUI_PID_StoreSt

56、ate-設定設備最新輸入消息,其實就是設定一個全局變量_State的值,這個函數(shù)通常在設備消息接收的任務當中調(diào)用,在模擬器中它是在LCD模擬顯示窗口的MOUSE消息中調(diào)用,這里必須說明的一個問題是,如果UCGUI在處理某些WM_TOUCH消息時用去時間過多的話,那么就會丟失掉部分WM_TOUCH消息,因為UCGUI只是用一個變量來接收消息而沒有消息隊列或是一個數(shù)組來緩存未處理的消息,如果使用隊列那么必然會使消息處理更加復雜,所以如果需要在WM_TOUCH消息中處理一個用時比較長的操作,那么最好使用一個新建的任務來完成該操作,否則在此過程中不能再處理任何外設的其它的輸入操作,這里與WIN下面是一

57、樣的,不過WIN下面單任務情況下只是操作不能及時有反應,但不會丟失后面操作所產(chǎn)生的消息,因為它有消息隊列,在此我們也可以看到UCGUI中很多處理機制一切重簡.GUI_PID_Init-初始化設備相關,此處函數(shù)為空.2將新獲取的消息與函數(shù)內(nèi)靜態(tài)的舊消息變量進行比較,包括該消息發(fā)生點的屏幕坐標及外設操作狀態(tài)(是否按下):滑動操作外設消息結(jié)構如下:typedefstructintx,y;/消息發(fā)生點在屏幕中的x/y坐標.unsignedcharPressed;/滑動外設是否按下.GUI_PID_STATE;3如果支持圖形鼠標,則根據(jù)新消息屏幕位置設置當前使用的鼠標位置,如果此處不進行這個設置,則在打

58、開MOUSE支持后,MOUSE是無法移動的,在觸摸屏當中一般不要求畫出圖形鼠標,一般只有在PS/2鼠標設備時才必須畫出圖形鼠標,否則無法進行鼠標操作。4當新舊消息的操作狀態(tài)比較發(fā)生變化時處理該消息通過將消息中的外設按下與否的狀態(tài)相或的值是否為1來判斷,為1則表示狀態(tài)改變,否則不發(fā)送此消息到窗體進行處理,而是直接更新新消息到舊消息上,這里我說的情況是UCGUI3.24版源碼的處理情況,但是看現(xiàn)在最新的有源碼的3.90源碼當中就處理了此種情況下的消息為WM_MOUSEOVER,還有一個不同就是將操作狀態(tài)的變化即新舊消息中的是否按下不相等時作為一個獨立的消息WM_PID_STATE_CHANGED來

59、發(fā)送,除此之外的消息才處理為WM_TOUCH消息,但是只要真正理解了UCGUI3.24版源碼中消息處理的根本原理,理解新版源碼中的消息處理也是很容易的,其本質(zhì)并未變化,只是將消息分成了三種處理,這樣顯得更加明確。5構造WM_TOUCH消息所需用要的數(shù)據(jù),首先要獲取到當前焦點窗體句柄,當前焦點窗體是用WM_hCapture的全局變量記載,如果為0則調(diào)用函數(shù)WM_Screen2hWin()根據(jù)消息發(fā)生點的屏幕坐標來獲取WM_TOUCH消息的對應的窗體句柄,注意這個函數(shù)是根據(jù)窗體數(shù)據(jù)結(jié)構,從第一個創(chuàng)建的窗體WM_FirstWin開始來遞歸查找,先查找窗體的第一個子窗體,然后查找hNext兄弟窗體,要

60、注意理解此函數(shù),其遞歸查找的本質(zhì)就是按照屏幕上的窗體層疊次序,從最上層窗體開始查找,窗體的前后臺順序是由父子及兄弟關系決定的,即UCGUI窗體層疊規(guī)則為:窗體顯示在其下一個兄弟窗體hNext之前,父窗體顯示在子窗體之后;調(diào)整窗體的前后臺順序其實就是調(diào)整窗體在兄弟窗體間的位置,注意這里要遞歸的理解這句話。6比較新舊焦點窗體變量,初始舊焦點窗體變量值為0,每當處理消息后,如果是按下狀態(tài)的WM_TOUCH消息,則會將當前焦點窗體句柄更新到舊焦點窗體變量中保存;如果不是按下狀態(tài)的WM_TOUCH消息,則會在處理完消息后將舊焦點窗體變量賦為0值。這樣處理的原因如下:當操作外設沒有處于按下狀態(tài),此時進行滑

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論