了解并学会底层窗口的创建和实现有利于我们学习更高层次的框架以及一些封装,能加深我们对编程原理的理解。
今天总结一下底层窗口的创建,先呈上源码。
#include<windows.h>
窗口设计大致分为六个步骤
1、设计窗口
2、注册窗口
3、创建窗口
4、显示窗口
5、消息循环
6、写回调函数
1、设计窗口
int WINAPI WinMain(
//这里的WINAPI就是宏定义的__stdcall 指的是参数从右到左依次传递
_In_ HINSTANCE hInstance,//实例句柄
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,//命令行
_In_ int nShowCmd)
{
WNDCLASS wc;
//这里定义一个窗口结构体的对象wc
wc.cbClsExtra = 0;//类的额外内存,我们不需要额外内存,设为零
wc.cbWndExtra = 0;//窗口的附加内存,我们也设为零
wc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
//他的背景项,GetStockObject 返回的是一个 HGDIOBJ类型的值
//而hbrBackground需要接受的是一个HBRUSH类型的值,所以我们在
//GetStockObject的前面加上(HBRUSH)将其返回值强制转换为HBRUSH类型
//GRAY_BRUSH是参数,表示背景为灰色,还有WHITE_BRUSH\BLACK_BRUSH
//等等,另外的参数值可以查阅msdn手册
wc.hCursor = LoadCursor(hInstance, IDC_ARROW);
//这里就是一个加载光标的函数,第一个参数为实例句柄,后面一个是光标的类型
//IDC_ARROW就是一个常规的箭头光标,还有其他类型,比如IDC_HELP就是
//一个❓,IDC_HAND就是一只手,其他参数可以查阅MSDN手册
wc.hIcon = LoadIcon(NULL,IDI_ERROR);
//这里是一个加载窗口图标的函数后面加载的是一个标准图标所以前面的一个
//参数必须填为NULL,IDI_ERROR就是在窗口左上角加载一个叉子图标
wc.hInstance = hInstance;
//这里就是一个实例句柄,照着前面填就ok
wc.lpfnWndProc=WindowProc;
//这里是一个回调函数,就是窗口的消息处理函数,我们在后面来实现
wc.lpszClassName = TEXT("windows");
//创建窗口都要为窗口关联一个类,这里windows就是窗口的类名称
//TEXT是一个函数,可以自适应多字节和宽字节
wc.lpszMenuName = NULL;
//系统菜单如果我们不需要就填NULL
wc.style = 0;
//窗口风格填零就是窗口的默认风格
2、注册窗口
RegisterClass(&wc);
3、创建窗口
HWND hwnd = CreateWindow(wc.lpszClassName, TEXT("哈哈哈"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
//这里的参数分别为窗口类名 窗口标题 窗口风格WS_OVERLAPPEDWINDOW
//是混合风格 后面 CW_USEDEFAULT依次表示的默认的窗口坐标和宽高
//最后返回一个窗口句柄
4、显示和更新窗口
ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd);
5、消息循环
MSG msg;
//MSG是一个结构体,这里定义一个结构体对象
while (1)//死循环
{
if (GetMessage(&msg,hwnd,0,0)==FALSE)
//这个判断语句的意思就是当点击叉子之后就退出循环
{
break;
}
TranslateMessage(&msg);//翻译消息
DispatchMessage(&msg);//分发消息
//这里就需要了解消息循环机制了,不然不好懂,我下一篇博文会总结一下
//我对消息循环机制的理解
}
return 0;
}
6、回调函数,也就是消息处理函数
LRESULT CALLBACK WindowProc(
// CALLBACK也是定义的一个宏__stdcall表示参数从右到左依次传递
_In_ HWND hWnd,
_In_ UINT Msg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
switch (Msg)
{
case WM_CLOSE:
//当我们点击叉子的时候系统会发出WM_CLOSE消息
//当接收到WM_CLOSE消息就调用DestroyWindow函数,DestroyWindow函数被
//调用以后就会销毁窗口,但是窗口进程并没有被销毁。DestroyWindow函数
//被调用以后就会发出WM_DESTROY消息
DestroyWindow(hWnd);
break;
case WM_DESTROY:
//接受到WM_DESTROY消息后就会调用PostQuitMessage函数销毁进程,这时候
//程序完全退出
PostQuitMessage(0);
break;
//这后面是一些消息处理
case WM_LBUTTONDOWN:
{
//WM_LBUTTONDOWN表示鼠标左键按下
int xPos = LOWORD(lParam);
int yPos = HIWORD(lParam);
//上面两行代码用于获取鼠标坐标
char buf[1024];
wsprintf(buf, TEXT("x=%d,y=%d"), xPos, yPos);
//wsprint是一个字符串转接函数,具体用法可以查阅msdn
MessageBox(hWnd, buf, TEXT("左键"), MB_OK);
//这里弹出一个窗口打印鼠标坐标,参数类型可以查阅MSDN
break;
}
case WM_KEYDOWN:
//WM_KEYDOWN是一个键盘弹起之前,按下之后的一个消息
MessageBox(hWnd, TEXT("键盘按下"), TEXT("键盘"), MB_OK);
//如果按下键盘就会弹出一个窗口打印一串字符“键盘按下”
break;
case WM_PAINT:
{
PAINTSTRUCT pt;
// PAINTSTRUCT是一个绘图结构体,我们可以把它比喻成一个画家
//定义一个对象pt
HDC hdc = BeginPaint(hWnd, &pt);
TextOut(hdc, 100, 300, TEXT("HELLO"), strlen("HELLO"));
EndPaint(hWnd, &pt);
}
}
return DefWindowProc(hWnd, Msg, wParam, lParam);
//这里是回调函数返回值
}
后面会写一篇博文讲解消息循环机制和windows字符集,以及与Windows字符集相关的TEXT自适应函数解答本文的一些疑惑。谢谢观看!