查遍了很多资料,没能找到一个完整的编写绘画板的博客,而且很多代码都是需要用积分下载的,这对新手是真的不够友好啊。我目前也还在学习,用此方法记录和巩固一下,并且为新手指个路,希望不要像我一样全靠自己摸索。下面进入正题。
Win32程序的入口函数是 WinMain , 和控制台程序的入口函数main类似。如下:
#include
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
return 0;
}
Windows程序入口函数:
WINAPI 代表_stdcall(一个宏) 参数的传递顺序:从右到左 依次入栈,并且在函数返回前 清空堆栈
hInstance 代表当前应用程序实例句柄
hPrevInstance 代表上一个应用程序句柄,在win32 环境下,参数一般为NULL
lpCmdLine 即 char* argv[]
nShowCmd 显示方式,例如最大化,最小化,正常
创建窗口总共分为六步,依次是:
1、设计窗口
2、注册窗口
3、创建窗口
4、显示和更新
5、通过循环取消息
6、处理消息(窗口过程)
我在代码中标注了一下注释,对照着看帮助理解。代码块是分开解释,直接按照顺序整合到WinMain函数中即可。在总结中,有完整的代码。每次更新都会将完整的代码附在后面。
//1、设计窗口
2 wnc;//窗口类
wnc.cbClsExtra = 0;//类 额外内存
wnc.cbWndExtra = 0;//窗口 额外内存
wnc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);//背景
wnc.hCursor = LoadCursor(NULL, IDC_ARROW); //光标。第一个参数为NULL,代表使用系统提供的光标
wnc.hIcon = LoadIcon(NULL, IDI_APPLICATION); //图标
wnc.hInstance = hInstance;//应用程序的实例句柄,传入WinMain中的形参
wnc.lpfnWndProc = WindowProc; //窗口过程函数,回调函数
wnc.lpszClassName = TEXT("WIN");//窗口的类名称
wnc.lpszMenuName = NULL;//菜单名
wnc.style = CS_HREDRAW | CS_VREDRAW;//横向重绘和纵向重绘,设置之后才会出现WM_PAINT消息
//2、注册窗口
RegisterClass(&wnc);
//3、创建窗口
/*
lpClassName 类名,和上面保持一致
lpWindowName 窗口标题名称
dwStyle 风格 WS_OVERLAPPEDWINDOW混合风格
x 坐标 CW_USEDEFAULT默认值
y 坐标
nWidth 宽
nHeight 高
hWndParent 父窗口
hMenu 菜单
hInstance 当前实例句柄
lpParam 附加值 鼠标附加值
*/
HWND hwnd = CreateWindow(wnc.lpszClassName, TEXT("绘画板-Win32 by 小黄"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, wnc.hInstance, NULL);
//4、显示和更新
ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd);
//5、通过循环取消息
/*
MSG 结构体
HWND hwnd; 主窗口句柄
UINT message; 具体的消息
WPARAM wParam; 附加消息,通常是键盘消息
LPARAM lParam; 附加消息,通过是鼠标消息
DWORD time; 消息产生的时间
POINT pt; 附加消息,鼠标坐标信息
*/
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) //循环获取消息
{
/*
LPMSG lpMsg, // address of structure with message
HWND hWnd, // handle of window,为NULL时,代表接收所有的窗口的消息
UINT wMsgFilterMin, // first message ,最大和最小的过滤的消息,一般填入0
UINT wMsgFilterMax // last message. 填0代表接收所有的消息
*/
//翻译消息
//有的消息不能直接执行,
//比如ctrl+C是复制消息,因此需要翻译,并且重新进入消息队列排队
TranslateMessage(&msg);
//分发消息
DispatchMessage(&msg);
}
在设计窗口时,在下面这句代码中传递进去的便是窗口回调函数。
wnc.lpfnWndProc = WindowProc; //窗口过程函数,回调函数
接下来编写该函数
//6、窗口过程
/*
HWND hwnd, 消息所属的窗口句柄
UINT uMsg, 具体消息名称 WM_xxxxxxxx 消息名
WPARAM wParam, 键盘附加消息
LPARAM lParam 鼠标附加消息
*/
// #define CALLBACK __stdcall
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CLOSE:
//所有xxxWindow结尾的消息,不会进入消息队列,而是直接执行
DestroyWindow(hwnd); //DestroyWindow 发送另一个消息 WM_DESTROY
break;
case WM_DESTROY:
PostQuitMessage(NULL);
break;
default:
break;
}
//返回值默认处理方式
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
这次是先创建窗口,接下来会在此次创建的窗口的基础上编写绘画板。持续更新中。。。
本次完整代码如下:
#include //底层实现窗口的头文件
//6、窗口过程
/*
HWND hwnd, 消息所属的窗口句柄
UINT uMsg, 具体消息名称 WM_xxxxxxxx 消息名
WPARAM wParam, 键盘附加消息
LPARAM lParam 鼠标附加消息
*/
// #define CALLBACK __stdcall
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CLOSE:
//所有xxxWindow结尾的消息,不会进入消息队列,而是直接执行
DestroyWindow(hwnd); //DestroyWindow 发送另一个消息 WM_DESTROY
break;
case WM_DESTROY:
PostQuitMessage(NULL);
break;
default:
break;
}
//返回值默认处理方式
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
//Windows程序入口函数
//WINAPI代表_stdcall(一个宏) 参数的传递顺序:从右到左 依次入栈,并且在函数返回前 清空堆栈
//hInstance 当前应用程序实例句柄
//hPrevInstance 上一个应用程序句柄,在哪win32 环境下,参数一般为NULL
//lpCmdLine 即 char* argv[]
//nShowCmd 显示方式,例如最大化,最小化,正常
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
//1、设计窗口
//2、注册窗口
//3、创建窗口
//4、显示和更新
//5、通过循环取消息
//6、处理消息(窗口过程)
//1、设计窗口
WNDCLASS wnc;//窗口类
wnc.cbClsExtra = 0;//类 额外内存
wnc.cbWndExtra = 0;//窗口 额外内存
wnc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);//背景
wnc.hCursor = LoadCursor(NULL, IDC_HAND); //光标。第一个参数为NULL,代表使用系统提供的光标
wnc.hIcon = LoadIcon(NULL, IDI_ERROR); //图标
wnc.hInstance = hInstance;//应用程序的实例句柄,传入WinMain中的形参
wnc.lpfnWndProc = WindowProc; //窗口过程函数,回调函数
wnc.lpszClassName = TEXT("WIN");//窗口的类名称
wnc.lpszMenuName = NULL;//菜单名
wnc.style = CS_HREDRAW | CS_VREDRAW;//横向重绘和纵向重绘,设置之后才会出现WM_PAINT消息
//2、注册窗口
RegisterClass(&wnc);
//3、创建窗口
/*
lpClassName 类名,和上面保持一致
lpWindowName 窗口标题名称
dwStyle 风格 WS_OVERLAPPEDWINDOW混合风格
x 坐标 CW_USEDEFAULT默认值
y 坐标
nWidth 宽
nHeight 高
hWndParent 父窗口
hMenu 菜单
hInstance 当前实例句柄
lpParam 附加值 鼠标附加值
*/
HWND hwnd = CreateWindow(wnc.lpszClassName, TEXT("绘画板-Win32 by 小黄"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, wnc.hInstance, NULL);
//4、显示和更新
ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd);
//5、通过循环取消息
/*
MSG 结构体
HWND hwnd; 主窗口句柄
UINT message; 具体的消息
WPARAM wParam; 附加消息,通常是键盘消息
LPARAM lParam; 附加消息,通过是鼠标消息
DWORD time; 消息产生的时间
POINT pt; 附加消息,鼠标坐标信息
*/
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) //循环获取消息
{
/*
LPMSG lpMsg, // address of structure with message
HWND hWnd, // handle of window,为NULL时,代表接收所有的窗口的消息
UINT wMsgFilterMin, // first message ,最大和最小的过滤的消息,一般填入0
UINT wMsgFilterMax // last message. 填0代表接收所有的消息
*/
//翻译消息
//有的消息不能直接执行,
//比如ctrl+C是复制消息,因此需要翻译,并且重新进入消息队列排队
TranslateMessage(&msg);
//分发消息
DispatchMessage(&msg);
}
//6、窗口过程
//对回调函数的编写
return 0;
}