對窗口創建的詳細解釋
============
·窗口的注冊
一個窗口的風格, 總是要根據窗口類來決定的, 同時, 窗口類決定了處理窗口消息所使用的函數(窗口過程)。 當定義好窗口類對象並完成對象屬性后, 如果想要建立這個窗口必須調用函數RegisterClass來注冊窗口類, RegisterClass的函數原型如下:
ATOM RegisterClass(CONST WNDCLASS *lpWndClass);
該函數只有一個參數, 一個指向一個WNDCLASS結構的指針, 現在, 我們再來看一下WNDCLASS窗口類的結構, 下面是等效定義, 和WINUSER.H中的WNDCLASS效果相同, 但WINUSER.H中是通過定義tagWNDCLASSA(ASCII版本)和tagWNDCLASSW(Unicode版本), 然后進行 :
#ifdef UNICODE typedef WNDCLASSW WNDCLASS; typedef PWNDCLASSW PWNDCLASS; typedef NPWNDCLASSW NPWNDCLASS; typedef LPWNDCLASSW LPWNDCLASS; #else typedef WNDCLASSA WNDCLASS; typedef PWNDCLASSA PWNDCLASS; typedef NPWNDCLASSA NPWNDCLASS; typedef LPWNDCLASSA LPWNDCLASS; #endif // UNICODE
來實現 WNDCLASS的定義, 在效果上和以下定義是相同的:
typedef struct tagWNDCLASS { UINT style; //窗口樣式 WNDPROC lpfnWndProc; //回調函數 int cbClsExtra; //窗口類擴展 int cbWndExtra; //窗口實例擴展 HINSTANCE hInstance; //窗口實例句柄 HICON hIcon; //窗口最小化圖標 HCURSOR hCursor; //窗口采用鼠標指針樣式 HBRUSH hbrBackground; //窗口背景顏色 LPCWSTR lpszMenuName; //窗口菜單 LPCWSTR lpszClassName; //窗口類名 } WNDCLASS, *PWNDCLASS;
在WinMain主函數中, 我們使用WNDCLASS創建了一個窗口類對象:wndclass, 並且對wndclass的屬性做了如下設置:
wndclass.style = CS_HREDRAW | CS_VREDRAW ; //窗口樣式 wndclass.lpszClassName = szAppName ; //窗口類名 wndclass.lpszMenuName = NULL ; //窗口菜單:無 wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH) ; //窗口背景顏色 wndclass.lpfnWndProc = WndProc ; //窗口消息處理函數 wndclass.cbWndExtra = 0 ; //窗口實例擴展:無 wndclass.cbClsExtra = 0 ; //窗口類擴展:無 wndclass.hInstance = hInstance ; //窗口實例句柄 wndclass.hIcon = LoadIcon( NULL, IDI_APPLICATION ) ; //窗口最小化圖標:使用缺省圖標 wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ) ; //窗口采用箭頭光標
下面我們來詳細看下WNDCLASS的這些成員:
1>. wndclass.style = CS_HREDRAW | CS_VREDRAW ;
style屬性決定着窗口的風格, 可以通過C語言的或運算組合出不同風格類型的窗口, 在WINUSER.H頭文件中定義着這些標識符以及其值, 所有的前綴為CS_的標識符如下:
/* * Class styles */ #define CS_VREDRAW 0x0001 #define CS_HREDRAW 0x0002 #define CS_DBLCLKS 0x0008 #define CS_OWNDC 0x0020 #define CS_CLASSDC 0x0040 #define CS_PARENTDC 0x0080 #define CS_NOCLOSE 0x0200 #define CS_SAVEBITS 0x0800 #define CS_BYTEALIGNCLIENT 0x1000 #define CS_BYTEALIGNWINDOW 0x2000 #define CS_GLOBALCLASS 0x4000 #define CS_IME 0x00010000
2>. wndclass.lpszClassName = szAppName ;
賦予窗口一個名稱, 可以使用ASCII版本的字符串也可以使用Unicode版本的字符串, 需要注意的是, 這里的窗口名稱並不是指窗口標題。
3>. wndclass.lpszMenuName = NULL ;
指定窗口類的菜單, 由於我們這個窗口沒有使用菜單, 所以為NULL, 具體的用法以后肯定會學習到;
4>. wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH) ;
窗口的背景顏色, 這里使用的是以白色作為填充, 填充白色這是常見的做法, 如果你願意, 也可以填充為其他的一些樣式, 這里是一些樣式的標識符:
#define WHITE_BRUSH 0 #define LTGRAY_BRUSH 1 #define GRAY_BRUSH 2 #define DKGRAY_BRUSH 3 #define BLACK_BRUSH 4 #define NULL_BRUSH 5 #define HOLLOW_BRUSH NULL_BRUSH #define WHITE_PEN 6 #define BLACK_PEN 7 #define NULL_PEN 8 #define OEM_FIXED_FONT 10 #define ANSI_FIXED_FONT 11 #define ANSI_VAR_FONT 12 #define SYSTEM_FONT 13 #define DEVICE_DEFAULT_FONT 14 #define DEFAULT_PALETTE 15 #define SYSTEM_FIXED_FONT 16
5>. wndclass.lpfnWndProc = WndProc ;
將窗口的消息處理函數設置為我們自定義的WndProc函數。
6>. wndclass.cbWndExtra = 0 ;
7>. wndclass.cbClsExtra = 0 ;
這兩個屬性用來維護結構中預留的一些額外空間, 程序可以根據需要要使用這些額外空間, 通過匈牙利命名的cbClsExtra、cbWndExtra中的cb可以知道, 這些成員表示一個"字節數", 由於我們這個窗口沒有使用到額外空間, 所以將這個兩個屬性賦值為0;
8>. wndclass.hInstance = hInstance ;
表示應用程序的實例句柄, hInstance的來源是WinMain的一個參數;
9>. wndclass.hIcon = LoadIcon( NULL, IDI_APPLICATION ) ;
加載一個位圖作為程序標題欄最左側的小圖標, 我們這里加載了一個系統的默認圖標, 后面的學習這將會學習到如何從磁盤加載我們自定義的圖標.
10>. wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ) ;
與LoadIcon類似, 加載鼠標的指針位圖;
完成這是個窗口類成員屬性的初始化后, 我們就可以通過RegisterClass來注冊窗口了, 如果注冊成功, 將返回一個具有唯一標識已注冊的類的一個原子, 如果函數失敗,返回0。
·窗口的創建
成功注冊窗口類后, 我們就可以呼叫CreateWindow函數對窗口進行創建了, CreateWindow函數的原型如下:
HWND CreateWindow( LPCTSTR lpClassName, //窗口類名稱 LPCTSTR lpWindowName, //窗口標題 DWORD dwStyle, //窗口樣式 int x, //窗口初始x坐標 int y, //窗口初始y坐標 int nWidth, //窗口初始x方向尺寸 int nHeight, //窗口初始y方向尺寸 HWND hWndParent, //父窗口句柄 HMENU hMenu, //窗口菜單句柄 HANDLE hlnstance, //程序實例句柄 LPVOID lpParam //創建參數 );
函數返回的是創建成功后的窗口的句柄。 需要說明的幾點:
1>.參數一: LPCTSTR lpClassName
參數LPCTSTR lpClassName,為窗口的名稱, 我們需要傳入的參數就是剛才我們在窗口類注冊的窗口類名稱, 這樣使用CreateWindow建立的窗口就能與注冊的窗口進行關聯。
2>. 參數三: DWORD dwStyle
參數三為窗口的樣式, 示例中創建的是一個普通的層疊窗口樣式, WS_OVERLAPPEDWINDOW, 打開WINUSER.H頭文件, 對於WS_OVERLAPPEDWINDOW是這樣定義的:
#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | \ WS_CAPTION | \ WS_SYSMENU | \ WS_THICKFRAME | \ WS_MINIMIZEBOX | \ WS_MAXIMIZEBOX)
可以看出, WS_OVERLAPPEDWINDOW樣式實際上是通過一些標識符通過或的組合, 此外我們還可以通過組合設計我們自己的樣式, 這些標識符在WINUSER.H的定義如下:
#define WS_OVERLAPPED 0x00000000L //產生一個層疊的窗口。一個層疊的窗口有一個標題條和一個邊框。與WS_TILED風格相同。 #define WS_POPUP 0x80000000L //創建一個彈出式窗口。該風格不能與WS_CHLD風格同時使用。 #define WS_CHILD 0x40000000L //創建一個子窗口。這個風格不能與WS_POPUP風格合用。 #define WS_MINIMIZE 0x20000000L //創建一個初始狀態為最小化的窗口。僅與WS_OVERLAPPED風格一起使用。 #define WS_VISIBLE 0x10000000L //創建一個最初可見的窗口。 #define WS_DISABLED 0x08000000L //創建一個初始狀態為禁止的窗口。 #define WS_CLIPSIBLINGS 0x04000000L //排除子窗口之間的相對區域。 #define WS_CLIPCHILDREN 0x02000000L //創建一個初始狀態為禁止的子窗口。一個禁止狀態的窗口不能接受來自用戶的輸入信息。 #define WS_MAXIMIZE 0x01000000L //創建一個初始狀態為最大化狀態的窗口。 #define WS_CAPTION 0x00C00000L //創建一個有標題框的窗口(包括WS_BODER風格)。 #define WS_BORDER 0x00800000L //創建一個單邊框的窗口。 #define WS_DLGFRAME 0x00400000L //創建一個帶對話框邊框風格的窗口。這種風格的窗口不能帶標題條。 #define WS_VSCROLL 0x00200000L //創建一個有垂直滾動條的窗口。 #define WS_HSCROLL 0x00100000L //創建一個有水平滾動條的窗口。 #define WS_SYSMENU 0x00080000L //創建一個在標題條上帶有窗口菜單的窗口,必須同時設定WS_CAPTION風格。 #define WS_THICKFRAME 0x00040000L //創建一個具有可調邊框的窗口,與WS_SIZEBOX風格相同。 #define WS_GROUP 0x00020000L //指定一組控制的第一個控制。 #define WS_TABSTOP 0x00010000L //創建一個控制,這個控制在用戶按下Tab鍵時可以獲得鍵盤焦點。按下Tab鍵后使鍵盤焦點轉移到下一具有WS_TABSTOP風格的控制。 #define WS_MINIMIZEBOX 0x00020000L //創建一個具有最小化按鈕的窗口。 #define WS_MAXIMIZEBOX 0x00010000L //創建一個具有最大化按鈕的窗口。 #define WS_TILED WS_OVERLAPPED //產生一個層疊的窗口。一個層疊的窗口有一個標題和一個邊框。與WS_OVERLAPPED風格相同。 #define WS_ICONIC WS_MINIMIZE //創建一個初始狀態為最小化的窗口。僅與WS_OVERLAPPED風格一起使用。 #define WS_SIZEBOX WS_THICKFRAME //創建一個具有厚邊框的窗口,可以通過厚邊框來改變窗口大小。 #define WS_TILEDWINDOW WS_OVERLAPPEDWINDOW //創建一個具有WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU,WS_THICKFRAME,WS_MINIMIZEBOX和WS_MAXIMIZEBOX風格的重疊式窗口。
關於這些樣式的詳細說明可以查閱MSDN Library(推薦)或到百科查詢。
·窗口的顯示
使用CreateWindow函數成功創建好窗口后, 這個窗口就被在保存在一段內存中了, 但是此時窗口還不能顯示在屏幕上, 我們需要使用ShowWindow函數來將建立好的窗口顯示出來, ShowWindow函數的原型如下:
BOOL ShowWindow( HWND hWnd, int iCmdShow );
參數一為剛才通過CreateWindow函數窗口出的窗口句柄, 參數二為窗口的顯示方式, 由WinMain函數的int iCmdShow接收該值, 常用的顯示方式有:
SW_HIDE //隱藏窗口並激活其他窗口; SW_MAXIMIZE //最大化; SW_MINIMIZE //最小化指定的窗口並且激活在Z序中的下一個頂層窗口; SW_RESTORE //激活並顯示窗口。如果窗口最小化或最大化,則系統將窗口恢復到原來的尺寸和位置; SW_SHOW //在窗口原來的位置以原來的尺寸激活和顯示窗口; SW_SHOWMAXIMIZED //激活窗口並將其最大化; SW_SHOWMINIMIZED //激活窗口並將其最小化; SW_SHOWMINNOACTIVE //窗口最小化,激活窗口仍然維持激活狀態;
SW_SHOWNA //以窗口原來的狀態顯示窗口。激活窗口仍然維持激活狀態; SW_SHOWNOACTIVATE //以窗口最近一次的大小和狀態顯示窗口。激活窗口仍然維持激活狀態; SW_SHOWNORMAL //激活並顯示一個窗口。如果窗口被最小化或最大化,系統將其恢復到原來的尺寸和大小;
·窗口的更新
當窗口客戶區需要進行更新時, UpdateWindow函數就會被調用, 並繞過消息隊列直接發送一個WM_PAINT的消息給窗口過程函數WndProc進行相應處理, UpdateWindow函數的原型如下:
BOOL UpdateWindow( HWND hWnd );
該函數只有一個參數, 參數為需要更新的窗口句柄; 函數調用成功返回值為非0, 調用失敗時返回值為0。
明天學習窗口過程WndProc是如何處理這些消息的。
--------------------
Wid, 2012.10.09
上一篇: C語言Windows程序設計->第四天->詳解我的窗口(上)