今天啥都別說了,分了21個bug,而且有兩個新功能要做,我的心哇涼哇涼的了,感嘆生不逢時,要是大傢伙都還在樹上吃香蕉的時候就出生就不用每天忙得跟狗一樣寫碼子了,擦,實在不行攤上個李剛爹也行啊!!
第三章上篇當中,哥說過,第三章主要可以用兩句話來展開“創建和顯示窗口,接受和處理消息”,並且以創建什麼窗口爲疑問介紹了WNDCLASS結構變量各個字段的含義。
創建和顯示窗口,接受和處理消息”中的創建什麼樣的窗口講完了,初始化了WNDCLASS變量之後需要註冊,可能有人問,爲什麼要註冊?直接拽過來用不就好了?這他孃的也不怪我,人家就那麼設計的,這就相當於,他孃的都是高中生,你學 數理化,人家也學數理化 ,但臨高考的時候你不能說你學過數理化都能直接參加高考,丫的要報名啊,自教育局註冊一下,就是這個道理,你要讓windows知道你要用這個類型創建窗口,RegisterClass(&wndClass);
接下來就該是怎麼創建窗口了,CreateWindow。CreateWindw的參數很多,比他孃的WNDCLASS還多一個,WNDCLASS只是指定了窗口的一般樣式,在創建窗口到時候你需要指定另外的一些窗口細節,比如窗口的大小了,在桌面上的位置等,HWND hWnd = CreateWindow(className,//窗口類名稱
TEXT("title"),//窗口標題
WS_OVERLAPPEDWINOW, //窗口樣式
CW_USEDEFAULT, //x座標
CW_USEDEFAULT, //y座標
CW_USEDEFAULT, //寬度
CW_USEDEFAULT, //高度
NULL, //父窗口句柄
NULL, //菜單
hInstance, //程序實例
NULL ,
)
最後一個參數說一下,最後一個參數是一個指向一個值得指針,這個值就是CreateWindow產生WM_CREATE消息的時候傳遞給回調函數的,通過回調函數的lparam參數傳遞。
好了,窗口創建好了,創建好了只是在系統中創建好了,在內存中存在了,但是跟屏幕沒半毛錢關係,因爲你只是在系統中註冊了,在內存中創建了,你又沒搞在屏幕上,所以你要用UpdateWindow,你可以這樣理解,UpdateWindow就是通過你在WNDCLASS和CreateWindow中設置的那些值映射到屏幕上屏幕上,在屏幕上無效的區域映射爲有效,還有窗口位置,大小,背景色等,UpdateWindow(hWnd)。
映射完了要幹嘛?要顯示,ShowWindow。首先要指定show哪個window,其次我們知道窗口有最大化,最小化等,所以要指定show成什麼樣子,所以ShowWindow有兩個參數ShowWindow(hWnd,SW_SHOWNORMAL),SW_SHOWNORMAL就是根據CreateWindow中設置的窗口大小和位置顯示,我們用的是CW_USEDEFAULT,也就是使用系統默認值,其次還可以用SW_SHOWMAXIMIZED和SW_SHOWMINNOACTIVE表示最大化和只在任務欄顯示。
好了,現在是窗口既創建了,又顯示了,接着該處理消息了。這個消息其實要說的非常多,所謂的面向事件的處理機制,說白了就是他孃的兵來將擋,水來土掩,你對窗口乾了什麼,窗口就根據你對它幹了啥來處理,比如你丫用鼠標點了它,或者關閉了它,但是我們要清楚一點,你不管對它做了什麼,操作系統都會向這個窗口發送你對它幹了什麼的消息,系統默認處理了一部分消息,但是如果你想搞的不一樣,不使用默認處理,那你就需要自己重新處理這些消息。
消息處理之一:在窗口創建的時候,操作系統就會爲該窗口生成一個消息隊列,記住是隊列!先進去先被搞!你在這個窗口上點擊鼠標,或者敲鍵盤等,操作系統都會捕獲到你在這個窗口範圍內幹了這些事,從而生成對應的消息放到你這個窗口的消息隊列裏。
消息處理之二:除了上面說的,操作系統會捕獲消息放到對應窗口的消息隊列之外,操作系統還能直接繞過這個隊列將一些消息直接發送個窗口處理過程,至於什麼是窗口處理過程,下面馬上就說。
現在先來看放到消息對列裏的消息,要知道你的爪子可能一直在點窗口,所以消息就一直往隊列里加,你就需要一直檢索隊列, 所以需要用while。
MSG msg;
while(GetMessage(&msg, NULL ,0 ,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
MSG:就是個結構體,用來存儲獲取從隊列裏獲取的消息;
typedef struct tagMSg
{
HWND hwnd; //窗口句柄
UINT message; //系統預定義好了的消息標識符,比如WM_PAINT
WPARAM wparam; //消息參數,取決於具體消息
LPARAM lparam; //消息參數,取決於具體消息
DWORD time; //消息進入消息隊列的時間
POINT point; //消息發生時候,鼠標的位置
}
好了,不管是放到消息隊列裏,還是直接發送給窗口,都需要有個函數來處理這些消息,這個函數就是傳說中的窗口過程函數,也叫回調函數,這個函數不是隨便寫的,有固定的格式,當然,我指的是返回值和參數名字沒什麼特殊,可以隨便起,操,說的隨便起是指符合規範的前提下隨便起,我們這裏就叫callBackWndProc吧。
這個函數的固定格式爲 LRESULT CALLBACK XXX(HWND hWnd, UINT message, WPARAM wparam, LPARAM lparam)
LRESULT :指的是從窗口程序或者回調函數返回的32位值。
CALLBACK :作用跟WINAPI其實是一樣的,但是WINAPI一般用於修飾動態鏈接庫中導出函數,CALLBACK僅用於修飾回調函數 。
HWND hWnd, UINT message, WPARAM wparam, LPARAM lparam 這四個參數跟MSG結構中的四個字段是一個含義。
媽的,心情不好,今晚早點睡了,明天寫第三章最後一部分---窗口過程函數
到現在爲止,進行的代碼如下:
#include <windows.h>
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
PSTR szCmdLine,
int iCmdLine)
{
TCHAR* className = "firstWindow";
WNDCLASS wndClass;
wndClass.hInstance = hInstance;
wndClass.style = CS_HREDRAW|CS_VREDRAW;
wndClass.lpszClassName = className;
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.lpszMenuName = NULL;
wndClass.lpfnWndProc = callBackWndProc //暫時假設回調函數名字爲callBackWndProc
RegisterClass(&wndClass);
HWND hwnd = CreateWindow(className,
TEXT("title"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
UpdateWindow(hwnd);
ShowWindow(hwnd, SW_SHOWNORMAL);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}