創建屬於自己的窗口
==================
·創建窗口前的准備
在創建窗口前我們先來熟悉幾個名詞, 這些名詞現在可以暫時不去透徹的進行理解, 只需要印象中知道有這么回事就行。
1>. 窗口
"窗口"這個我們都已經十分熟悉了, 在Windows中, 一個應用程序窗口上一般會在標題欄上顯示程序的名稱, 緊挨着標題欄的菜單欄, 或許還會有狀態欄、滾動條等其他"裝飾品"。
2>. 控件
在一些應用程序中, 我們經常可以在程序的界面上(窗口)看到一些按鈕(Push Button)、文本框(Text Box)、列表框(List Box)、滾動條(Scroll Bar)等, 這些對象通常被稱為控件, 在《Windows程序設計》一書中, 還被稱為"子窗口"、"控件窗口"或"子窗口控件"。
3>. 窗口類
在建立一個窗口前, 我們必須首先注冊一個"窗口類"(Windows Class), 接觸過面向對象的朋友應該會首先想到面向對象當中的"類", 但是, 這里"窗口類"中的"類"並不是指面向對象當中的那個"類"。
在這里我們可以把"窗口類"理解為一個結構體, 結構體的成員就是窗口的一些屬性, 例如窗口的標題是什么、窗口使用什么樣的小圖標以及窗口的風格之類的屬性, 一個窗口就是一個結構體的對象, 結構體成員的屬性決定着窗口的屬性。
4>. 消息循環
在Windows程序設計中, 消息循環是個不得不提的概念, Windows操作系統是以消息驅動的, 消息隊列是指在一個應用程序運行時, Windows操作系統會為該應用程序建立一個"消息隊列", 這個消息隊列用來存放該程序可能創建的各種窗口的消息, 當用戶對應用程序進行操作時, 例如點擊一個按鈕、調整下窗口的大小等, 此時Windows會立即把這一消息告訴應用程序, 使應用程序能作出相應的動作。
筆者覺得有比較強調一下上一段中的最后一句"此時Windows會立即把這一消息告訴應用程序, 使應用程序能作出相應的動作。", 我們在創建一個應用程序時, 不用想着什么時候才能從用戶那得到指令, 因為操作系統會即時告訴我們用戶此時是否對程序進行了操作, 對於沒有接觸過Windows編程的朋友們這點可能有點難以理解, 簡單來說就是像如何獲取一個按鈕是否被單擊, 或者如何獲取用戶此時是否在調整窗口大小之類的代碼Windows已經幫我們完成了, 我們只需要等待着Windows給我們發消息就行, 如何判斷消息類型以及處理這些消息, 在代碼上通常我們用while配合一個巨大的switch來完成,。
5>. 窗口的過程函數
當一個窗口建立之后, 就可以從Windows那里不斷的接收到Windows發來的消息, 接收到消息后我們就需要一個函數來處理這些消息, 可以簡單的理解為, 這個用來處理接收到的消息的函數就稱為窗口過程函數或者回調函數。
下面我們來嘗試着看一個創建一個基本窗口的代碼。
·嘗試創建自己的窗口
代碼如下:
#include <windows.h> LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ) ; //聲明用來處理消息的函數 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow ) { static TCHAR szAppName[] = TEXT("MyWindow") ; HWND hwnd ; MSG msg ; 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 ) ; //窗口采用箭頭光標 if( !RegisterClass( &wndclass ) ) { //注冊窗口類, 如果注冊失敗彈出錯誤提示 MessageBox( NULL, TEXT("窗口注冊失敗!"), TEXT("錯誤"), MB_OK | MB_ICONERROR ) ; return 0 ; } hwnd = CreateWindow( //創建窗口 szAppName, //窗口類名 TEXT("我的窗口"), //窗口標題 WS_OVERLAPPEDWINDOW, //窗口的風格 CW_USEDEFAULT, //窗口初始顯示位置x:使用缺省值 CW_USEDEFAULT, //窗口初始顯示位置y:使用缺省值 CW_USEDEFAULT, //窗口的寬度:使用缺省值 CW_USEDEFAULT, //窗口的高度:使用缺省值 NULL, //父窗口:無 NULL, //子菜單:無 hInstance, //該窗口應用程序的實例句柄 NULL // ) ; ShowWindow( hwnd, iCmdShow ) ; //顯示窗口 UpdateWindow( hwnd ) ; //更新窗口 while( GetMessage( &msg, NULL, 0, 0 ) ) //從消息隊列中獲取消息 { TranslateMessage( &msg ) ; //將虛擬鍵消息轉換為字符消息 DispatchMessage( &msg ) ; //分發到回調函數(過程函數) } return msg.wParam ; } LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) { HDC hdc ; //設備環境句柄 PAINTSTRUCT ps ; //繪制結構 RECT rect; //矩形結構 switch( message ) //處理得到的消息 { case WM_CREATE: //窗口創建完成時發來的消息 MessageBox( hwnd, TEXT("窗口已創建完成!"), TEXT("我的窗口"), MB_OK | MB_ICONINFORMATION ) ; return 0; case WM_PAINT: //處理窗口區域無效時發來的消息 hdc = BeginPaint( hwnd, &ps ) ; GetClientRect( hwnd, &rect ) ; DrawText( hdc, TEXT( "Hello, 這是我自己的窗口!" ), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER ) ; EndPaint( hwnd, &ps ) ; return 0 ; case WM_LBUTTONDOWN: //處理鼠標左鍵被按下的消息 MessageBox( hwnd, TEXT("鼠標左鍵被按下。"), TEXT("單擊"), MB_OK | MB_ICONINFORMATION ) ; return 0; case WM_DESTROY: //處理窗口關閉時的消息 MessageBox( hwnd, TEXT("關閉程序!"), TEXT("結束"), MB_OK | MB_ICONINFORMATION ) ; PostQuitMessage( 0 ) ; return 0; } return DefWindowProc( hwnd, message, wParam, lParam ) ; //DefWindowProc處理我們自定義的消息處理函數沒有處理到的消息 }
--------------------
先簡單介紹這段代碼, 在主函數WinMain中的窗口類對象wndclass我們定義了窗口的相關屬性, 嘗試注冊窗口類並調用CreateWindow創建窗口, 創建完成后用ShowWindow讓窗口顯示出來, 我們還使用了個while用來從消息隊列里獲取並分發消息給程序, 我們還定義了一個過程函數WndProc用來處理系統發來的消息。
編譯運行后, 如果沒有錯誤將首先看到一個窗口建立成功與否的對話框, 當創建窗口失敗時彈出一個錯誤對話框並關閉程序。
當窗口被創建時首先Windows會發給我們一條創建完成的消息"WM_CREATE", 在我們的消息處理函數WinProc中有switch-case語句對該消息進行了處理, 就是彈出一個窗口創建完成的對話框。
同樣, 我們還處理了當窗口的客戶區(內容部分)被改變時發來的的"WM_PAINT"消息進行了處理, 讓"Hello, 這是我創建的窗口!"始終顯示在窗口中心。
"WM_LBUTTONDOWN"消息是當用戶在客戶區按下鼠標左鍵時發來的消息, 我們作出相應的動作為彈出一個鼠標左鍵被按下的對話框。
當用戶點擊窗口的關閉按鈕時, "WM_DESTROY"消息就會發來, 我們作出的動作是彈出"關閉程序!"的對話框並且退出程序。
今天的學習先到這里, 明天我們詳細學習下整個創建窗口的代碼。
--------------------
Wid, 2012.10.08