WINDOWS程序設計之窗口過程

創建一個窗口的過程
1:創建一個窗口首先要註冊一個窗口類,用一個窗口過程處理窗口消息;
2:windows的程序調用
LoadIcon:加載圖標
LoadCursor:加載鼠標指針
GetStockObject:獲取圖形對象
RigisterClass:爲程序窗口註冊窗口類
MessageBox:顯示消息框
CreateWindow:根據窗口類創建一個窗口
ShowWindow:在屏幕上顯示窗口
UpdateWindow:指示窗口刷新自身
GetMessage:從消息隊列中獲取消息
TranslateMessage:轉換某些鍵盤信息
DispatchMessage:將消息發送給窗口過程
PlaySound:播放一個聲音文件
BeginPaint:開始窗口繪製
GetClientRect:獲取窗口客戶區的尺寸
DrawText:顯示文本串
EndPaint:結束窗口繪製;
PostQuitMessage:消息隊列中插入一條 退出信息
DefWindowProc:執行默認的消息處理
3:大寫標識符的前綴表示的含義
CS:類風格選項
CW:創建窗口選項
DT:繪製文本選項
IDI:圖標ID號
IDC:光標ID號
MB:消息框選項
SND聲音選項
WM:窗口消息
WS:窗口風格

4:新的數據類型
在源程序中的其他標識符是新的數據類型,在Windows頭文件中使用typedef語句加以定義;
UINT:一個unsigned int(無符號整數)32位
PSTR:指向一個字符串的指針(char*)
WPARAM:定義成一個UINT(32位無符號整數)
LPARAM:定義成一個LONG(32位有符號整數)
LRESULT:是WndProc函數的返回值,定義成一個LONG
WINAPI:WinMain函數的類型,頭文件中的所有Windows函數都被指定成這個類型
CLASSBACK:WndProc指定爲該類型(WINAPI和CLASSBACK均爲__stdcall類型,指在Windows本身和用戶的應用程序之間發生的函數調用的特殊調用序列)
5:Windows頭文件定義的四種數據結構
MSG:消息結構
WNDCLASS:窗口類結構
PAINTSTRUCT:繪圖結構
RECT:矩形結構

6:三個句柄
句柄是一個32位的數,代表一個對象;程序通過調用Windows函數獲取句柄,在Windows函數中引用句柄,以引用它所代表的對象,句柄的實際值對程序無關緊要,
但Windows模塊知道如何使用它來引用相應的對象。
HINSTANCE:實例句柄(程序自身)
HWND:窗口句柄
HDCP:設備描述句柄
7:匈牙利表示法(變量名既能描述變量的作用,又描述了其數據類型,這就能比較容易的避免產生數據類型不搭配的錯誤)
在Windows程序中,使用匈牙利表示法給變量命名,變量名以一個或者多個小寫字母開始,這些字母表示變量的數據類型;
sz 表示以零結尾的字符串
hInstance,hPrevInstance中的h前綴表示句柄
iCmdShow中的i前綴表示 整數
wPraram 更適合叫uiPraram(無符號整數)
c:char活WHAR或TCHAR的前綴
by:BYTE(無符號字符)的前綴
n:short的前綴
i:int的前綴
x,y:int分別用作x座標或y座標
cx,cy:int分別用作x長度,和y的長度;c代表count;
b,f:b代表bool;f代表flag;
w:WORD(無符號short);
l:LONG(長整數)
dw:DWORD(無符號長整數)
fn:function(函數)
s:string(串)
sz:以零字節結尾的串
lpfn:只想函數的長指針
h:句柄
p:指針
cb:字節數
hbr:一個刷子的句柄
8:結構的命名
可以用結構名的小寫,或結構名縮寫的小寫給結構名命名;
9:註冊窗口類
窗口總是在窗口類的基礎上創建的,窗口類用以標示處理窗口信息的消息過程。
(1)首先註冊一個窗口類WNDCLASS wndclass
在程序創建窗口之前,必須首先調用RegisterCLASS註冊一個窗口類;
該函數只要一個參數,即一個指向類型爲WNDCLASS的結構指針。
補充:WNDCLASS結構簡介
此結構包括兩個指向字符串的域,因此結構在WINUSER.H頭文件中定義了兩種不用的方式。(ASCII版本和Unicode版本)
ASCII版本的WNDCLASSA
typedef struct tagWNDCLASSA
{
   UINT style;           類風格
   WNDPROC lpfnWndPROC;  基於這個類創建的窗口所使用的窗口過程的地址;
   int cbClsExtra;
   int cbWndExtra;       類結構和窗口結構中預留一些額外空間,程序可以根據需要使用預留的空間
   HINSTANCE hinstance;  程序的實例句柄,是WinMain的參數之一
   HICON hicon;          爲所有基於這個窗口類建立的窗口設置一個圖標,圖標是一個小的位圖圖像
   HCURSOR hCursor;
   HBRUSH hbrBackground;
   LPCSTR lpszMinuName;
   LPCSTR lpszClassName;   窗口類的文本名
}
WNDCLASS,*PWNDCLASSA,NEAR *NPWNDLASSA,FAR *LPWINDCLASSA;
補充:WINUSER.H定義了WNDCLASS和指向WNDCLASS的結構體,及一些向後兼容的代碼
(2)初始化wndclass中的各個域
wnd.style = CS_HREDRAW|CS_VREDRAW;
wnd.lpfnWndProc = WndProc;
將窗口類的窗口過程設置爲WndProc,及HEELLOWIN.H中的第二個函數,用於處理基於這個窗口類創建的所有窗口的全部消息。WndProc是函數的指針;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;

wndclass.hInstance = hInstance;
設置程序的實例句柄
wndclass.hIcon = LOADIcon(NULL,IDI_APPLICATION)
此函數返回圖標的句柄,用於設置hIcon的值,第一個參數設置爲Null,來獲取預先定義的圖標句柄;第二個參數設置爲IDI_APPLICATION(爲圖標的標識符,在WINUSER.H中定義)
wndclass.hCusor = LoadCursor(null, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHIT_BRUSH);
指定這個類創建的窗口背景的顏色;
補充:刷子,刷子是圖形學上的一個術語,指用來填充一個域的着色像素模式。Windows有幾個標準刷子;GetStockObject調用返回一個白色刷子句柄                          wndclass.lpszMenuName = NULL;指定窗口類菜單
wndclass.lpszClassName = szAppName;給出類名,該串由ASCII字符組成還是有Unicode字符組成取決於是否定義了UNICODE標識符    
(3)調用RigisterClass來註冊這個窗口類;
Register(&wndclass)這個函數只有一個參數,即指向WNDCLASS的指針
補充:許多windows函數需要分配內存,如RegisterClass函數需要分配內存,以保存關於窗口類的信息。
(4)創建窗口
窗口類定義了窗口的一般特徵,因此可以使用同一窗口類創建許多不同的窗口,調用CreateWindow創建窗口時,可能指定窗口有關的更詳細的信息;
補充:窗口類及窗口的區別,以及createWindow函數和RegisterClass函數的區別
傳給RegisterClass的函數信息在一個數據結構中說明,傳遞給CreateWindows的函數的信息作爲函數的單獨參數。
補充:HWMD hwnd;創建一個窗口的句柄,存放在變量hwnd中,HWND爲窗口句柄類型,Windows中每個窗口都有一個句柄,程序用句柄引用窗口。許多windows函數需要使用hwnd作爲參數,這樣,Windows才能知道函數是針對那個窗口的,如果一個程序創建了很多窗口,則每個窗口均有一個句柄。(窗口句柄是Windows程序處理的最重要的句柄之一);
窗口風格:WS_OVERLAPPEDWINDOW是一個標準風格的函數
(5)顯示窗口
ShowWindow(hwnd, iCmdShow);
UpateWindow(hwnd);
(6)消息循環
調用UpdateWindow之後,窗口就出現在視頻顯示器上,程序現在必須準備讀入用戶用鍵盤和鼠標輸入的數據。Windows 爲當前運行的每個Windows程序維護一個消息隊列。當發生輸入事件之後,Windows將事件轉換爲一個消息,並將消息放在程序的消息隊列中。
程序通過執行一塊被成爲消息循環的代碼從消息隊列中取出消息
while(GetMessage(&msg,NULL,0,0))
{
   TracslateMessage(&msg);
   DispatchMessage(&msg);
}
補充:msg變量是類型爲MSG的結構,MSG類型在WINUSER.H中定義如下:
type struct tagMSG
{
  HWND hwnd;  該程序擁有的唯一窗口
  UINT message; 消息標示符。是一個數值,用來標示消息。對於每個消息,均有一個標識符與之對應。這些標示符定義在Windows頭文件中。以前綴WM開頭。
                例如:用戶將鼠標光標放在客戶區域之內,並按下左鍵,則Windows在消息隊列中放入一消息,該消息的message域等於WM_LBUTTONDOWN(是一個常量);
  WPARAM wParam;32的消息參數,其含義和數值根據消息的不同而不同;
  LPARAM IParam;一個32位的消息參數,其含義與消息有關
  DWORD time;  消息放入消息隊列的時間
  POINT pt;    消息放入隊列的鼠標座標
}

typedef struct tagPOINT
{
   LONG X;
   LONG Y;
}
發生輸入事件後,Windows將其轉換爲一個消息放入消息隊列中,程序從消息隊列取出消息,只要從消息隊列取出消息的message域不爲WM_QUIT,則GetMessage就返回一個非零值;
TranslateMessage(&msg);將msg結構傳給Windows,
DispatchMessage(&msg);
又將msg結構回傳給Windows。然後Windows將該消息發送給適當的窗口過程,讓它進行處理。
注:Windows調用窗口過程,這個窗口過程是WndPro函數,處理完消息後,WndProc返回到Windows,此時Windows還停留在DispatchMessage調用中,在結束DispatchMessage調用的處理之後,Windows回到HELLOWIN中,並且從下一個GetMessage調用開始循環消息;
(7)窗口過程
注:準備性工作,註冊窗口類-》創建窗口-》顯示窗口-》程序進入消息循環-》從消息隊列中取出一條消息-》窗口過程進行處理
窗口過程確定了在窗口的客戶區域中顯示些什麼,以及窗口怎麼響應用戶輸入;
一個WINDOWS程序可以包含多個窗口過程,一個窗口過程總是於調用RigisterClass註冊的特定窗口類相關聯。CreateWindow函數根據特定的窗口類創建一個窗口。但基於一個窗口類可以創建多個窗口。
窗口過程的定義:
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM iParam)
程序通常不直接調用窗口調用,窗口調用通常有WINDOWS本身調用。通過SendMessage函數,程序能夠直接調用它自己的窗口過程
(8)處理消息
窗口過程接受的每個消息均是用一個數值來標示的,也就是傳給窗口過程的message參數。WINDOWS頭文件WINUSER.H爲每個消息參數定義爲WM爲前綴的標識符;
WINDOWS程序員使用switch和case結構來確定窗口過程接受的是什麼消息,以及如何適當的處理它,窗口過程在處理消息時必須返回零,窗口過程不予處理的所有消息應該被傳給名爲DefWindowProc的WINDOWS函數。從DefWindowProc返回的值必須有窗口過程返回。
補充:調用DefWindowProc來爲窗口過程不予處理的所有消息提供默認處理。
(9)播放聲音文件
窗口過程接受的第一個消息,WM_CREATE,也是WndProc選擇處理的第一個消息。
接受消息的機制:
當程序調用CreateWindow函數時,WINDOWS調用Wndproc,將其第一個參數設置爲句柄,第二個參數設置爲wm_create;
WndProc處理WM_CREATE消息,並將控制返回給WINDOWS;
WINDOWS從CreateWindow調用中返回到程序,繼續下一步的處理。
(10) WM_PAINT消息
這個消息在Windows程序設計中很重要,當窗口客戶區域的一部分或全部變爲無效時,以至於必須重新刷新時,將有這個消息通知程序;
補充:最初創建窗口時,整個客戶區都是無效的,因爲程序還沒有在窗口上畫什麼東西。第一個WM_PAINT消息指示窗口過程在客戶區域上畫些東西;
     用戶改變窗口大小時,客戶區重新變得無效,然後窗口過程將收到一個wm_paint消息
對wm_paint的處理總是從一個BeginPaint調用開始,以一個EndPaint調用哪個結束;這兩個調用中,第一個參數是程序的窗口句柄,第二個參數是指向類型爲PAINTSTRUCT的結構指針(該結構中包含一些窗口過程,用來刷新客戶區域的指針);BeginPain調用使整個客戶區有效,並返回一個設備描述表句柄。設備描述表是指物理輸出設備及其他設備驅動程序。在窗口的客戶區域顯示文本和圖形需要設備描述表句柄(不能用從BeginPaint返回的設備描述表句柄在客戶區域之外繪圖);EndPaint釋放設備描述表句柄,使之不在有效;
     調用完BeginPaint之後,WndProc接着調用GetClientRect;其第一個參數是程序窗口的句柄,第二個參數是一個指向RECT結構類型的指針;
補充:rectangle結構有四個LONG域,分別爲left,top,right,botton。表示窗口客戶區域的尺寸,left和top設置爲0,right和bottom設置爲客戶區域的寬度和高度。(像素點數);
將RECT指針作爲DrawText的第四個參數傳遞,不在做其他處理;當客戶區變得無效,WndProc就接受一個新的wm_paint消息,WndProc通過調用GetClientRect獲取變化後的窗口大小,並在新窗體的中央現實文本。
(11)WM_DESTROY消息
該消息提示,WINDOWS正在根據用戶輸入的命令來清楚窗口。(用戶單擊CLoce按鈕或者在程序的系統菜單上選擇close時發生);程序通過調用PostQuitMessage以標準方式響應WM_DESTROY消息;該函數在程序的消息隊列中插入一個WM_QUIT消息,當GetMessage取得一個wm_quit消息時,返回0,這將導致WinMain退出消息循環並終止程序;
(12)Window編程的難點
在HELLOWIN中,WinMain包含了註冊窗口類,創建窗口,從消息隊列中取得消息和發送消息等相關的代碼;
程序所有的動作均在窗口過程中發生,實際上,WINDOWS程序所做的一切都是響應發送給窗口過程的消息;
(13)別調用我,我會調用你
在WINDOWS程序設計中,WINDOWS有1000個以上的函數可供程序調用,但WINDOWS也在調用用戶程序;例如前面定義的窗口過程WndProc,窗口過程與一個窗口類相關聯,窗口類是程序調用RegisterCLASS註冊的。基於該類創建的窗口使用這個窗口過程來處理窗口的所有消息,WINDOWS通過調用窗口過程來給窗口發送一個消息;
所有的WndProc調用都以消息的方式進行,大多數WINDOWS程序中,程序的主要部分都用來處理消息;(WINDOWS可以發送給窗口過程的消息通常都以WM打頭的標識符,並且都在WINUSER.H中定義);在WINDOWS中窗口中發生的一切都以消息的形式傳給窗口過程,然後窗口過程以某種方式響應這個消息;
注:一個窗口過程能處理基於同一個窗口創建的多個窗口的消息,參數hwnd讓窗口過程知道那個窗口接受消息;
(14)WinProc窗口過程的各個參數
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM IParam)
參數message是WM_SIZW,消息WM_SIZE的參數wParam
參數wPARAM在WINUSER.H中定義爲數字0到4表明窗口是非最小化還是非最大化
參數IParam包含新窗口的大小;
注:有時候,DefWindowProc處理完消息後會產生其他消息;窗口過程用來處理消息;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章