在这一章中,主要讲述了Windows下创建窗口的基本步骤和其中的有关问题。
在Windows的消息处理机制中,窗口过程函数被调用的过程如下所示:
第一步:在进行窗口类的设计时,将窗口过程函数的地址赋给lpfnWndProc成员变量。
第二步:调用RegisterClass(&wndClass)注册窗口类,那么系统就有了我们所编写的窗口过程函数的地址。
第三步:当应用程序接受到某一窗口的消息时,首先用TranslateMessage(&msg)将虚拟键转化为字符信息,然后调用DispatchMessage(&msg)将消息回传给系统
Windows窗口设计共分为6个步骤:
1. 窗口类的设计
2. 窗口类的注册
3. 正式创建窗口
4. 窗口类的移动、显示与更新
5. 设计消息循环过程
6. 窗口类的注销
1. 窗口类的设计
首先利用WNDCLASSEX建立一个窗口类,然后对这个类的各个属性进行赋值即可。
WNDCLASSEX wndClass = { 0 };
wndClass.***= ***;
2.窗口类的注册
RegisterClass(&wndclass)函数进行注册即可,若注册失败,返回-1。if (!RegisterClassEx(&wndClass))
return -1;
3.窗口类的创建
利用CreatateWindow()函数创建正式窗口,并且返回一个窗口句柄。
HWND hwnd = CreateWindow(***);
4.窗口类的移动、显示与更新
MoveWindow(hwnd,x,y, WINDOW_WIDTH, WINDOW_HEIGHT, true);
ShowWindow(hwnd, nShwoCmd);
UpdateWindow(hwnd);
5.设计消息循环过程
在Windows的消息循环过程中,共有两种方式,一种是PeekMessage,另一种是GetMessage,它们都是从消息队列中获取信息。GetMessage它会等待消息,如果消息队列中一条消息也没有它就会一直等待,直到消息的出现(如果没有消息程序会一直休眠卡死在这个地方不能继续执行)。而PeekMessage是无论消息队列中有没有信息,它都立即返回,使程序继续执行之后的指令。
MSG msg = { 0 };
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
在向窗口传递好信息后,需要对传递的信息进行处理,这个时候就需要窗口过程函数WindowProc进行处理
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT: //若是客户区重绘消息
ValidateRect(hwnd, NULL); //更新客户区的显示
break;
case WM_KEYDOWN:
if (wParam == VK_ESCAPE) //如果被按下的是ESC
DestroyWindow(hwnd);
break;
case WM_DESTROY: //若是窗口摧毁消息
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
当所有信息处理完后,需要对窗口类进行注销,这时需要用UnregisterClass()。
当一切完成之后,对一个窗口类的操作也就结束了。
下面附上示例程序代码:#include<Windows.h>
#define WINDOW_WIDTH 600
#define WINDOW_HEIGHT 800
#define WINDOW_TITLE L"致我们的游戏开发梦想—程序基本框架"
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShwoCmd)
{
//窗口创建第一步:设计
WNDCLASSEX wndClass = { 0 };
wndClass.cbClsExtra = 0;
wndClass.cbSize = sizeof(WNDCLASSEX);
wndClass.cbWndExtra = 0;
wndClass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hIcon = (HICON)::LoadImage(NULL, L"nike.ico", IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR | LR_LOADFROMFILE);
wndClass.hInstance = hInstance;
wndClass.lpfnWndProc = WndProc;
wndClass.lpszClassName = L"ForTheDreamOfGameDevelop";
wndClass.lpszMenuName = NULL;
wndClass.style = CS_HREDRAW | CS_VREDRAW;
//窗口创建第二步:注册
if (!RegisterClassEx(&wndClass))
return -1;
//窗口创建第三步:创建
HWND hwnd = CreateWindow(L"ForTheDreamOfGameDevelop", WINDOW_TITLE, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL);
//窗口创建第四步:窗口的移动、显示和更新
MoveWindow(hwnd, 250, 80, WINDOW_WIDTH, WINDOW_HEIGHT, true);
ShowWindow(hwnd, nShwoCmd);
UpdateWindow(hwnd);
//第五步:消息循环过程
MSG msg = { 0 };
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
//第六步:窗口类的注销
UnregisterClass(L"ForTheDreamOfGameDevelop", hInstance);
return 0;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT: //若是客户区重绘消息
ValidateRect(hwnd, NULL); //更新客户区的显示
break;
case WM_KEYDOWN:
if (wParam == VK_ESCAPE) //如果被按下的是ESC
DestroyWindow(hwnd);
break;
case WM_DESTROY: //若是窗口摧毁消息
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}