|
本文中51黑將向你詳細(xì)介紹,在我們天天都要用的windows操作系統(tǒng)里面,一個(gè)窗口究竟是怎么產(chǎn)生和工作的.
1. 窗口類參數(shù)的意義
要WinMain登記窗口類,首先要填寫一個(gè)WNDCLASS結(jié)構(gòu),其定義如下所示:
typedef struct_WNDCLASSA
{
UINT style ; //窗口類風(fēng)格
WNDPROC lpfnWndProc ; //指向窗口過(guò)程函數(shù)的指針
int cbClsExtra ; //窗口類附加數(shù)據(jù)
int cbWndExtra; //窗口附加數(shù)據(jù)
HINSTANCE hInstance ; //擁有窗口類的實(shí)例句柄
HICON hIcon ; //最小窗口圖標(biāo)
HCURSOR hCursor ; //窗口內(nèi)使用的光標(biāo)
HBRUSH hbrBackground ; //用來(lái)著色窗口背景的刷子
LPCSTR lpszMenuName; //指向菜單資源名的指針
LPCSTR lpszClassName ; // 指向窗口類名的指針
}
其中參數(shù)的意義如下:
(1)第一個(gè)參數(shù):成員style控制窗口的某些重要特性,在WINDOWS.H中定義了一些前綴為CS的常量,在程序中可組合使用這些常量.也可把sytle設(shè)為0.本程序中為wc.style=CS_HREDRAW | CS_VREDRAW,它表示當(dāng)窗口的縱橫坐標(biāo)發(fā)生變化時(shí)要重畫整個(gè)窗口。你看:無(wú)論你怎樣拉動(dòng)窗口的大小,那行字都會(huì)停留在窗口的正中部,而假如把這個(gè)參數(shù)設(shè)為0的話,當(dāng)改動(dòng)窗口的大小時(shí),那行字則不一定處于中部了。
(2)第二個(gè)參數(shù):lpfnWndProc包括一個(gè)指向該窗口類的消息處理函數(shù)的指針,此函數(shù)稱為窗口過(guò)程函數(shù)。它將接收Windows發(fā)送給窗口的消息,并執(zhí)行相應(yīng)的任務(wù)。其原型為:
long FAR PASCAL WndProc(HWND,unsigned,WORD,LONG);并且必須在?於x中回調(diào)它。WndProc是一個(gè)回調(diào)函數(shù)(見第五節(jié)),如果暫時(shí)無(wú)法理解這個(gè)模糊的概念意味著什么,可先放過(guò),等到講消息循環(huán)時(shí)再詳談。
(3)第三,四個(gè)參數(shù):cbWndExtra域指定用本窗口類建立的所有窗口結(jié)構(gòu)分配的額外字節(jié)數(shù)。當(dāng)有兩個(gè)以上的窗口屬于同一窗口類時(shí),如果想將不同的數(shù)據(jù)和每個(gè)窗口分別相對(duì)應(yīng)。則使用該域很有用。這般來(lái)講,你只要把它們?cè)O(shè)為0就行了,不必過(guò)多考慮。
(4)第五個(gè)參數(shù):hInstance域標(biāo)識(shí)應(yīng)用程序的實(shí)例hInstance,當(dāng)然,實(shí)例名是可以改變的。wc.hInstance= hInstance ;這一成員可使Windows連接到正確的程序。
(5)第六個(gè)參數(shù):成員hIcon被設(shè)置成應(yīng)用程序所使用圖標(biāo)的句柄,圖標(biāo)是將應(yīng)用程序最小化時(shí)出現(xiàn)在任務(wù)欄里的的圖標(biāo),用以表示程序仍駐留在內(nèi)存中。Windows提供了一些默認(rèn)圖標(biāo),我們也可定義自己的圖標(biāo),VC里面專有一個(gè)制作圖標(biāo)的工具。
(6)第七個(gè)參數(shù): hCursor域定義該窗口產(chǎn)生的光標(biāo)形狀。LoadCursor可返回固有光標(biāo)句柄或者應(yīng)用程序定義的光標(biāo)句柄。IDC_ARROW表示箭頭光標(biāo).
(7)第八個(gè)參數(shù):wc.hbrBackground域決定Windows用于著色窗口背景的刷子顏色,函數(shù)GetStockObject返回窗口的顏色,本程序中返回的是白色,你也可以把它改變?yōu)榧t色等其他顏色.試試看
(8)第九個(gè)參數(shù):lpszMenuName用來(lái)指定菜單名,本程序中沒(méi)有定義菜單,所以為NULL。
(9)第十個(gè)參數(shù):lpszClassName指定了本窗口的類名。
注冊(cè)窗口類如下:
if (!RegisterClass (&wc)) {
MessageBox (NULL, TEXT ("This program requiresWindows NT!"),
szAppName,MB_ICONERROR) ;
return 0 ;
}
-------------------2.創(chuàng)建顯示更新窗口-------------------------
注冊(cè)窗口類后,就可以創(chuàng)建窗口了,本程序中創(chuàng)建窗口的有關(guān)語(yǔ)句如下:
hwnd =CreateWindow (szAppName, //window class name
TEXT("歡迎你的到來(lái)!"), //window caption
WS_OVERLAPPEDWINDOW, //window style
CW_USEDEFAULT, //initial x position
CW_USEDEFAULT, //initial y position
CW_USEDEFAULT, //initial x size
CW_USEDEFAULT, //initial y size
NULL, //parent window handle
NULL, //window menu handle
hInstance, //program instance handle
NULL); //creation parameters
參數(shù)1:登記的窗口類名,這個(gè)類名剛才咱們?cè)谧?cè)窗口時(shí)已經(jīng)定義過(guò)了。
參數(shù)2:用來(lái)表明窗口的標(biāo)題。
參數(shù)3: 用來(lái)表明窗口的風(fēng)格,如有無(wú)最大化,最小化按紐啊什么的。
參數(shù)4,5: 用來(lái)表明程序運(yùn)行后窗口在屏幕中的坐標(biāo)值。
參數(shù)6,7: 用來(lái)表明窗口初始化時(shí)(即程序初運(yùn)行時(shí))窗口的大小,即長(zhǎng)度與寬度。
參數(shù)8: 在創(chuàng)建窗口時(shí)可以指定其父窗口,這里沒(méi)有父窗口則參數(shù)值為0。
參數(shù)9: 用以指明窗口的菜單,菜單以后會(huì)講,這里暫時(shí)為0。
最后一個(gè)參數(shù)是附加數(shù)據(jù),一般都是0。
CreateWindow()的返回值是已經(jīng)創(chuàng)建的窗口的句柄,應(yīng)用程序使用這個(gè)句柄來(lái)引用該窗口。如果返回值為0,就應(yīng)該終止該程序,因?yàn)榭赡苣硞(gè)地方出錯(cuò)了。如果一個(gè)程序創(chuàng)建了多個(gè)窗口,則每個(gè)窗口都有各自不同的句柄.
API函數(shù)CreateWindow創(chuàng)建完窗口后,要想把它顯示出現(xiàn),還必須調(diào)用另一個(gè)API函數(shù)ShowWindows.形式為:ShowWindow(hwnd, iCmdShow);
其第一個(gè)參數(shù)是窗口句柄,告訴ShowWindow()顯示哪一個(gè)窗口,而第二個(gè)參數(shù)則告訴它如何顯示這個(gè)窗口:最小化(SW_MINIMIZE),普通(SW_SHOWNORMAL),還是最大化(SW_SHOWMAXIMIZED)。WinMain在創(chuàng)建完窗口后就調(diào)用ShowWindow函數(shù),并把iCmdShow參數(shù)傳送給這個(gè)窗口。你可把iCmdShow改變?yōu)檫@些參數(shù)試試。
WinMain()調(diào)用完ShowWindow后,還需要調(diào)用函數(shù)UpdateWindow(hwnd),最終把窗口顯示了出來(lái)。調(diào)用函數(shù)UpdateWindow將產(chǎn)生一個(gè)WM_PAINT消息,這個(gè)消息將使窗口重畫,即使窗口得到更新.
-----------------3.消息循環(huán)------------------------
主窗口顯示出來(lái)了,WinMain就開始處理消息了,怎么做的呢?
Windows為每個(gè)正在運(yùn)行的應(yīng)用程序都保持一個(gè)消息隊(duì)列。當(dāng)你按下鼠標(biāo)或者鍵盤時(shí),Windows并不是把這個(gè)輸入事件直接送給應(yīng)用程序,而是將輸入的事件先翻譯成一個(gè)消息,然后把這個(gè)消息放入到這個(gè)應(yīng)用程序的消息隊(duì)列中去。應(yīng)用程序又是怎么來(lái)接收這個(gè)消息呢?這就講講消息循環(huán)了。
應(yīng)用程序的WinMain函數(shù)通過(guò)執(zhí)行一段代碼從她的隊(duì)列中來(lái)檢索Windows送往她的消息。然后WinMain就把這些消息分配給相應(yīng)的窗口函數(shù)以便處理它們,這段代碼是一段循環(huán)代碼,故稱為"消息循環(huán)"。這段循環(huán)代碼是什么呢?好,往下看:
在咱們的第二只小板凳中,這段代碼就是:
......
MSG msg; //定義消息名
while(GetMessage (&msg, NULL, 0,0))
{
TranslateMessage(&msg) ; //翻譯消息
DispatchMessage(&msg) ; //撤去消息
}
returnmsg.wParam ;
MSG結(jié)構(gòu)在頭文件中定義如下:
typedef structtagMSG
{
HWND hwnd;
UINTmessage;
WPARAMwParam;
LPARAMlParam;
DWORD time;
POINT pt;
} MSG,*PMSG;
MSG數(shù)據(jù)成員意義如下:
參數(shù)1:hwnd是消息要發(fā)送到的那個(gè)窗口的句柄,這個(gè)窗口就是咱們用CreateWindows函數(shù)創(chuàng)建的那一個(gè)。如果是在一個(gè)有多個(gè)窗口的應(yīng)用程序中,用這個(gè)參數(shù)就可決定讓哪個(gè)窗口接收消息。
參數(shù)2:message是一個(gè)數(shù)字,它唯一標(biāo)識(shí)了一種消息類型。每種消息類型都在Windows文件中定義了,這些常量都以WM_開始后面帶一些描述了消息特性的名稱。比如說(shuō)當(dāng)應(yīng)用程序退出時(shí),Windows就向應(yīng)用程序發(fā)送一條WM_QUIT消息。
參數(shù)3:一個(gè)32位的消息參數(shù),這個(gè)值的確切意義取決于消息本身。
參數(shù)4:同上。
參數(shù)5:消息放入消息隊(duì)列中的時(shí)間,在這個(gè)域中寫入的并不是日期,而是從Windows啟動(dòng)后所測(cè)量的時(shí)間值。Windows用這個(gè)域來(lái)使用消息保持正確的順序。
參數(shù)6:消息放入消息隊(duì)列時(shí)的鼠標(biāo)坐標(biāo).
消息循環(huán)以GetMessage調(diào)用開始,它從消息隊(duì)列中取出一個(gè)消息:
GetMessage(&msg,NULL,0,0),第一個(gè)參數(shù)是要接收消息的MSG結(jié)構(gòu)的地址,第二個(gè)參數(shù)表示窗口句柄,NULL則表示要獲取該應(yīng)用程序創(chuàng)建的所有窗口的消息;第三,四參數(shù)指定消息范圍。后面三個(gè)參數(shù)被設(shè)置為默認(rèn)值,這就是說(shuō)你打算接收發(fā)送到屬于這個(gè)應(yīng)用程序的任何一個(gè)窗口的所有消息。在接收到除WM_QUIT之外的任何一個(gè)消息后,GetMessage()都返回TRUE。如果GetMessage收到一個(gè)WM_QUIT消息,則返回FALSE,如收到其他消息,則返回TRUE。因此,在接收到WM_QUIT之前,帶有GetMessage()的消息循環(huán)可以一直循環(huán)下去。只有當(dāng)收到的消息是WM_QUIT時(shí),GetMessage才返回FALSE,結(jié)束消息循環(huán),從而終止應(yīng)用程序。均為NULL時(shí)就表示獲取所有消息。
消息用GetMessage讀入后(注意這個(gè)消息可不是WM_QUIT消息),它首先要經(jīng)過(guò)函數(shù)TranslateMessage()進(jìn)行翻譯,這個(gè)函數(shù)會(huì)轉(zhuǎn)換成一些鍵盤消息,它檢索匹配的WM_KEYDOWN和WM_KEYUP消息,并為窗口產(chǎn)生相應(yīng)的ASCII字符消息(WM_CHAR),它包含指定鍵的ANSI字符.但對(duì)大多數(shù)消息來(lái)說(shuō)它并不起什么作用,所以現(xiàn)在沒(méi)有必要考慮它。
下一個(gè)函數(shù)調(diào)用DispatchMessage()要求Windows將消息傳送給在MSG結(jié)構(gòu)中為窗口所指定的窗口過(guò)程。我們?cè)谥v到登記窗口類時(shí)曾提到過(guò),登記窗口類時(shí),我們?cè)付╓indows把函數(shù)WindosProc作為咱們這個(gè)窗口的窗口過(guò)程(就是指處理這個(gè)消息的東東)。就是說(shuō),Windows會(huì)調(diào)用函數(shù)WindowsProc()來(lái)處理這個(gè)消息。在WindowProc()處理完消息后,代碼又循環(huán)到開始去接收另一個(gè)消息,這樣就完成了一個(gè)消息循環(huán)。
Windows是一種非剝奪式多任務(wù)操作系統(tǒng)。只有的應(yīng)用程序交出CPU控制權(quán)后,Windows才能把控制權(quán)交給其他應(yīng)用程序。當(dāng)GetMessage函數(shù)找不到等待應(yīng)用程序處理的消息時(shí),自動(dòng)交出控制權(quán),Windows把CPU的控制權(quán)交給其他等待控制權(quán)的應(yīng)用程序。由于每個(gè)應(yīng)用程序都有一個(gè)消息循環(huán),這種隱式交出控制權(quán)的方式保證合并各個(gè)應(yīng)用程序共享控制權(quán)。一旦發(fā)往該應(yīng)用程序的消息到達(dá)應(yīng)用程序隊(duì)列,即開始執(zhí)行GetMessage語(yǔ)句的下一條語(yǔ)句。
當(dāng)WinMain函數(shù)把控制返回到Windows時(shí),應(yīng)用程序就終止了。應(yīng)用程序的啟動(dòng)消息循環(huán)前要檢查引導(dǎo)出消息循環(huán)的每一步,以確保每個(gè)窗口已注冊(cè),每個(gè)窗口都已創(chuàng)建。如存在一個(gè)錯(cuò)誤,應(yīng)用程序應(yīng)返回控制權(quán),并顯示一條消息。
但是,一旦WinMain函數(shù)進(jìn)入消息循環(huán),終止應(yīng)用程序的唯一辦法就是使用PostQuitMessage把消息WM_QUIT發(fā)送到應(yīng)用程序隊(duì)列。當(dāng)GetMessage函數(shù)檢索到WM_QUIT消息,它就返回NULL,并退出消息外循環(huán)。通常,當(dāng)主窗口正在刪除時(shí)(即窗口已接收到一條WM_DESTROY消息),應(yīng)用程序主窗口的窗口函數(shù)就發(fā)送一條WM_QUIT消息。
雖然WinMain指定了返回值的數(shù)據(jù)類型,但Windows并不使用返回值。不過(guò),在調(diào)試一應(yīng)用程序時(shí),返回值地有用的。通常,可使用與標(biāo)準(zhǔn)C程序相同的返回值約定:0表示成功,非0表示出錯(cuò)。PostQuitMessage函數(shù)允許窗口函數(shù)指定返回值,這個(gè)值復(fù)制到WM_QUIT消息的wParam參數(shù)中。為了的結(jié)束消息循環(huán)之后返回這個(gè)值,我們的第二只小板凳中使用了以下語(yǔ)句:
return msg.wParam ; //表示從PostQuitMessage返回的值
例如:當(dāng)Windows自身終止時(shí),它會(huì)撤消每個(gè)窗口,但不把控制返回給應(yīng)用程序的消息循環(huán),這意味著消息循環(huán)將永遠(yuǎn)不會(huì)檢索到WM_QUIT消息,并且的循環(huán)之后的語(yǔ)句也不能再執(zhí)行。Windows的終止前的確發(fā)送一消息給每個(gè)應(yīng)用程序,因而標(biāo)準(zhǔn)C程序通常會(huì)的結(jié)束前清理現(xiàn)場(chǎng)并釋放資源,但Windows應(yīng)用程序必須隨每個(gè)窗口的撤消而被清除,否則會(huì)丟失一些數(shù)據(jù)。
---------------------4.窗口過(guò)程,窗口過(guò)程函數(shù)-------------------------------------
如前所述,函數(shù)GetMessage負(fù)責(zé)從應(yīng)用程序的消息隊(duì)列中取出消息,而函數(shù)DispatchMessage()要求Windows將消息傳送給在MSG結(jié)構(gòu)中為窗口所指定的窗口過(guò)程。然后出臺(tái)的就是這個(gè)窗口過(guò)程了,這個(gè)窗口過(guò)程的任務(wù)是干什么呢?就是最終用來(lái)處理消息的,就是消息的處理器而已,那么這個(gè)函數(shù)就是WindowProc,在VisualC++6.0中按F1啟動(dòng)MSDN,按下面這個(gè)路徑走下來(lái):
PlatFormSDK-->UserInterface services-->Windowsuser Interface-->Windowing-->WindowProcedures-->WindowProcedureReference-->WindowsProcedureFunctions-->WindowProc
啊,太累了,不過(guò)我們終于的MSDN中找到了這個(gè)函數(shù),前幾次我講解這些API函數(shù)的時(shí)候,都是的知道的情況下搜索出來(lái)的,所以沒(méi)有詳細(xì)給出每個(gè)函數(shù)的具體位置,而這次我卻是一點(diǎn)點(diǎn)去找的,還好,沒(méi)被累死,體會(huì)到MSDN的龐大了吧,不過(guò)我用的是MSDN2000,是D版的,三張光盤裝。你用的MSDN如果按這個(gè)路徑走下去的話,可能會(huì)找不到,不過(guò)我想大致也是在這個(gè)位置了,找找看!。
LRESULT CALLBACKWindowProc
(
HWNDhwnd, // handle towindow
UINTuMsg, // messageidentifier
WPARAMwParam, // first messageparameter
LPARAMlParam // second messageparameter
);
這個(gè)函數(shù)這里被我們稱為WndProc.
下面講解:
不知你注意到了沒(méi)有,這個(gè)函數(shù)的參數(shù)與剛剛提到的GetMessage調(diào)用把返回的MSG結(jié)構(gòu)的前四個(gè)成員相同。如果消息處理成功,WindowProc的返回值為0.
Windows的啟動(dòng)應(yīng)用程序時(shí),先調(diào)用WinMain函數(shù),然后調(diào)用窗口過(guò)程,注意:在我們的這個(gè)程序中,只有一個(gè)窗口過(guò)程,實(shí)際上,也許有不止一個(gè)的窗口過(guò)程。例如,每一個(gè)不同的窗口類都有一個(gè)與之相對(duì)應(yīng)的窗口過(guò)程。無(wú)論Windows何時(shí)想傳遞一個(gè)消息到一窗口,都將調(diào)用相應(yīng)的窗口過(guò)程。當(dāng)Windows從環(huán)境,或從另一個(gè)應(yīng)用程序,或從用戶的應(yīng)用程序中得到消息時(shí),它將調(diào)用窗口過(guò)程并將信息傳給此函數(shù)?傊翱谶^(guò)程函數(shù)處理所有傳送到由此窗口類創(chuàng)建的窗口所得到的消息。并且窗口過(guò)程有義務(wù)處理Windows扔給它的任何消息。我們?cè)趯W(xué)習(xí)Windows程序設(shè)計(jì)的時(shí)候,最主要的就是學(xué)習(xí)這些消息是什么以及是什么意思,它們是怎么工作的。
令我們不解的是,在程序中我們看不出來(lái)是哪一個(gè)函數(shù)在調(diào)用窗口過(guò)程。它其實(shí)是一個(gè)回調(diào)函數(shù).前面已經(jīng)提到,Windows把發(fā)生的輸入事件轉(zhuǎn)換成輸入消息放到消息隊(duì)列中,而消息循環(huán)將它們發(fā)送到相應(yīng)的窗口過(guò)程函數(shù),真正的處理是在窗口過(guò)程函數(shù)中執(zhí)行的,在Windows中就使用了回調(diào)函數(shù)來(lái)進(jìn)行這種通信。
回調(diào)函數(shù)是輸出函數(shù)中特殊的一種,它是指那些在Windows環(huán)境下直接調(diào)用的函數(shù)。一個(gè)應(yīng)用程序至少有一個(gè)回調(diào)函數(shù),因?yàn)樵趹?yīng)用程序處理消息時(shí),Windows調(diào)用回調(diào)函數(shù)。這種回調(diào)函數(shù)就是我們前面提到的窗口過(guò)程,它對(duì)對(duì)應(yīng)于一個(gè)活動(dòng)的窗口,回調(diào)函數(shù)必須向Windows注冊(cè),Windows實(shí)施相應(yīng)操作即行回調(diào)。
每個(gè)窗口必須有一個(gè)窗口過(guò)程與之對(duì)應(yīng),且Windows直接調(diào)用本函數(shù),因此,窗口函數(shù)必須采用FARPASCAL調(diào)用約定。在我們的第二只小板凳中,我們的窗口函數(shù)為WndProc,必須注意這里的函數(shù)名必須是前面注冊(cè)的窗口類時(shí),向域wc.lpfnWndProc所賦的WndProc。函數(shù)WndProc就是前面定義的窗口類所生成的所有窗口的窗口函數(shù)。
在我們的這個(gè)窗口函數(shù)中,WndProc處理了共有兩條消息:WM_PAINT和WM_DESTROY.
窗口函數(shù)從Windows中接收消息,這些消息或者是由WinMain函數(shù)發(fā)送的輸入消息,或者是直接來(lái)自Windows的窗口管理消息。窗口過(guò)程檢查一條消息,然后根據(jù)這些消息執(zhí)行特定的動(dòng)作未被處理的消息通過(guò)DefWindowProc函數(shù)傳回給Windows作缺海上處理。
可以發(fā)送窗口函數(shù)的消息約有220種,所有窗口消息都以WM_開頭,這些消息在頭文件中被定義為常量。引起Windows調(diào)用窗口函數(shù)的原因有很多,,如改變窗口大小啊,改變窗口在屏幕上的位置啊什么的。
----------------5.處理消息----------------------------------
窗口過(guò)程處理消息通常以switch語(yǔ)句開始,對(duì)于它要處理的每一條消息ID都跟有一條case語(yǔ)句。大多數(shù)windowsproc都有具有下面形式的內(nèi)部結(jié)構(gòu)
switch(uMsgId)
{
caseWM_(something):
//這里此消息的處理過(guò)程
return0;
caseWM_(something else):
//這里是此消息的處理過(guò)程
ruturn0;
default:
//其他消息由這個(gè)默認(rèn)處理函數(shù)來(lái)處理
returnDefWindowProc(hwnd,uMsgId,wParam,lParam);
}
在處理完消息后,要返回0,這很重要-----它會(huì)告訴Windows不必再重試了。對(duì)于那些在程序中不準(zhǔn)備處理的消息,窗口過(guò)程會(huì)把它們都扔給DefWindowProc進(jìn)行缺省處理,而且還要返回那個(gè)函數(shù)的返回值。在消息傳遞層次中,可以認(rèn)為DefWindowProc函數(shù)是最頂層的函數(shù)。這個(gè)函數(shù)發(fā)出WM_SYSCOMMAND消息,由系統(tǒng)執(zhí)行Windows環(huán)境中多數(shù)窗口所公用的各種通用操作,例如,畫窗口的非用戶區(qū),更新窗口的正文標(biāo)題等等等等。
再提示一下,以WM_的消息在Windows頭文件中都被定義成了常量,如WM_QUIT=XXXXXXXXXXX,但我們沒(méi)有必要記住這個(gè)數(shù)值,也不可能記得住,我們只要知道WM_QUIT就OK了。
在第二只小板凳中我們只讓窗口過(guò)程處理了兩個(gè)消息:一個(gè)是WM_PAINT,另一個(gè)是WM_DESTROY,先說(shuō)說(shuō)第一個(gè)消息---WM_PAINT.
關(guān)于WM_PAINT: 無(wú)論何時(shí)Windows要求重畫當(dāng)前窗口時(shí),都會(huì)發(fā)該消息。也可以這樣說(shuō):無(wú)論何時(shí)窗口非法,都必須進(jìn)行重畫。哎呀,什么又是"非法窗口"?什么又是重畫。
在MSDN里面找有關(guān)這個(gè)方面的內(nèi)容
Platform SDK-->Graphics and Multimedia Services-->Windows GDI-->Painting and Drawing-->Using the WM_PAINTMessage-----終于找到了。
下面是一大套理論:
讓我們把Windows的屏幕想像成一個(gè)桌面,把一個(gè)窗口想像成一張紙。當(dāng)我們把一張紙放到桌面上時(shí),它會(huì)蓋住其他的紙,這樣被蓋住的其他紙上的內(nèi)容都看不到了。但我們只要把這張紙移開,被蓋住的其他紙上的內(nèi)容就會(huì)顯示出來(lái)了---這是一個(gè)很簡(jiǎn)單的道理,誰(shuí)都明白。
對(duì)于我們的屏幕來(lái)說(shuō),當(dāng)一個(gè)窗口被另一窗口蓋住時(shí),被蓋住的窗口的某些部分就看不到了,我們要想看到被蓋住的窗口的全部面貌,就要把另一個(gè)窗口移開,但是當(dāng)我們移開后,事情卻起了變化-----很可能這個(gè)被蓋住的窗口上的信息被擦除了或是丟失了。當(dāng)窗口中的數(shù)據(jù)丟失或過(guò)期時(shí),窗口就變成非法的了---或者稱為"無(wú)效"。于是我們的任務(wù)就來(lái)了,我們必須考慮怎樣在窗口的信息丟失時(shí)"重畫窗口"--使窗口恢復(fù)成以前的那個(gè)樣子。這也就是我們?cè)谶@第二只小板凳中調(diào)用UpdateWindow的原因。
你忘記了嗎?剛才我們?cè)?/font>(三)顯示和更新窗口 中有下面的一些文字:
WinMain()調(diào)用完ShowWindow后,還需要調(diào)用函數(shù)UpdateWindow,最終把窗口顯示了出來(lái)。調(diào)用函數(shù)UpdateWindow將產(chǎn)生一個(gè)WM_PAINT消息,這個(gè)消息將使窗口重畫,即使窗口得到更新.---這是程序第一次調(diào)用了這條消息。
為重新顯示非法區(qū)域,Windows就發(fā)送WM_PAINT消息實(shí)現(xiàn)。要求Windows發(fā)送WM_PAINT的情況有改變窗口大小,對(duì)話框關(guān)閉,使用了UpdateWindows和ScrollWindow函數(shù)等。這里注意,Windows并非是消息WM_PAINT的唯一來(lái)源,使用InvalidateRect或InvalidateRgn函數(shù)也可以產(chǎn)生繪圖窗口的WM_PAINT消息......
通常情況下用BeginPaint()來(lái)響應(yīng)WM_PAINT消息。如果要在沒(méi)有WM_PAINT的情況下重畫窗口,必須使用GetDC函數(shù)得到顯示緩沖區(qū)的句柄。這里面不再擴(kuò)展。詳細(xì)見MDSN。
這個(gè)BeginPaint函數(shù)會(huì)執(zhí)行準(zhǔn)備繪畫所需的所有步驟,包括返回你用于輸入的句柄。結(jié)束則是以EndPaint();
在調(diào)用完BeginPaint之后,WndProc接著調(diào)用GetClientRect:
GetClientRect(hwnd,&rect);
第一個(gè)參數(shù)是程序窗口的句柄。第二個(gè)參數(shù)是一個(gè)指針,指向一個(gè)RECT類型的結(jié)構(gòu)。查MSDN,可看到這個(gè)結(jié)構(gòu)有四個(gè)成員。
WndProc做了一件事,他把這個(gè)RECT結(jié)構(gòu)的指針傳送給了DrawText的第四個(gè)參數(shù)。函數(shù)DrawText的目的就是在窗口上顯示一行字----"你好,歡迎你來(lái)到VC之路!",有關(guān)這個(gè)函數(shù)的具體用法這里也沒(méi)必要說(shuō)了吧。
關(guān)于WM_DESTROY 這個(gè)消息要比WM_PAINT消息容易處理得多:只要用戶關(guān)閉窗口,就會(huì)發(fā)送WM_DESTROY消息(在窗口從屏幕上移去后)。
程序通過(guò)調(diào)用PostQuitMessage以標(biāo)準(zhǔn)方式響應(yīng)WM_DESTROY消息:
PostQuitMessage (0) ;
這個(gè)函數(shù)在程序的消息隊(duì)列中插入一個(gè)WM_QUIT消息。在(四)創(chuàng)建消息循環(huán)中我們?cè)羞@么一段話:
消息循環(huán)以GetMessage調(diào)用開始,它從消息隊(duì)列中取出一個(gè)消息:
.......
在接收到除WM_QUIT之外的任何一個(gè)消息后,GetMessage()都返回TRUE。如果GetMessage收到一個(gè)WM_QUIT消息,則返回FALSE,如收到其他消息,則返回TRUE。因此,在接收到WM_QUIT之前,帶有GetMessage()的消息循環(huán)可以一直循環(huán)下去。只有當(dāng)收到的消息是WM_QUIT時(shí),GetMessage才返回FALSE,結(jié)束消息循環(huán),從而終止應(yīng)用程序。
---------------------還有一個(gè)對(duì)本文的總結(jié)請(qǐng)看51黑2樓----------------------------------------
|
|