绘图消息(WM_PAINT)
概念
- 当产生无效区的时候,系统会发送VM_PAINT消息
- 无效区:窗口需要重新绘制的部分
- 设备上下文(hdc):可以理解为获取显示屏绘制属性的句柄
无效区产生时机
- 最小化恢复的时候
- 被覆盖的部分重新显示(win10 移除屏幕外)
- 窗口的尺寸被修改
- 还有一些API可以发送WM_PAINT消息(UpdateWindow)
- 拖动\鼠标移动\菜单,不会产生,因为系统做了优化
BeginPaint和GetDC的区别
- BeginPaint会清除无效区,GetDC不会.
- BeginPaint/EndPaint通常只在WM_PAINT消息中使用.
- 两个API清理内存的函数不同
键盘消息
消息类型
- 键盘按下(WM_KEYDOWN)
- 键盘弹起(WM_KEYUP)
相关API
- 将keydown消息转换为字符消息
-
将keydown消息转换为字符消息 WM_CHAR TranslateMessage(&msg)
-
注意WM_CHAR WM_KEYDOWN消息处理一个就可以了 不然会冲突默认进WM_KEYDOWN消息
-
派发消息到对应的窗口过程函数 DispatchMessage(&msg)
-
WM_CHAR 对应的只是字符键而不是按键如esc键什么的。其中,字符是指的0-127内的ASCII码
// Win32Test.cpp : 定义应用程序的入口点。
//
#include "stdafx.h"
#include "Win32Test.h"
void ShowErrorMessage()
{
LPVOID lpMsgBuf;
//将错误码转化为错误信息,参数可以抄MSDN
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR)&lpMsgBuf,
0,
NULL
);
// Process any inserts in lpMsgBuf.
// ...
// 弹出错误提示窗口.
MessageBox(NULL, (LPCTSTR)lpMsgBuf, TEXT("Error"), MB_OK | MB_ICONINFORMATION);
// Free the buffer.
LocalFree(lpMsgBuf);
}
LRESULT CALLBACK MyWindowPro
(HWND hwnd, // 窗口句柄
UINT uMsg, // 消息标识
WPARAM wParam, // 附加在消息上的参数
LPARAM lParam // 附加在消息上的参数
)
{
switch (uMsg)
{
//当产生无效区的时候,系统会发送VM_PAINT消息
case WM_PAINT:
{
/*使用beginPaint处理绘图消息*/
//BeginPaint会清除无效区,GetDC不会(不清除就会一直发送WM_PAINT消息).
//获取DC
PAINTSTRUCT ps;
HDC hDc = BeginPaint(hwnd, &ps);//此时会清除无效区
//绘制字符区域
RECT rc;
rc.left = 0;
rc.top = 0;
rc.right = 100;
rc.bottom = 100;
//绘制字符串
DrawText(hDc, TEXT("hello world"), 11, &rc, DT_CENTER);
//MessageBox(NULL, NULL, NULL, MB_OK);
EndPaint(hwnd, &ps);//用于释放内存
///*使用GetDC处理绘图消息*/
//GetDC不会清除无效区(不清除就会一直发送WM_PAINT消息)
//HDC hDc = GetDC(hwnd);
绘制字符区域
//RECT rc;
//rc.left = 100;
//rc.top = 100;
//rc.right = 1000;
//rc.bottom = 1000;
绘制字符串
//DrawText(hDc, TEXT("hello world"), 11, &rc, DT_CENTER);
//MessageBox(NULL, NULL, NULL, MB_OK);
//ReleaseDC(hwnd, hDc);//用于释放内存
break;
}
case WM_CHAR:
{
TCHAR sZ[0X255] = { 0 };
wsprintf(sZ, TEXT("%c"), wParam); //windows 当中的输入功能
MessageBox(hwnd, sZ, TEXT("输入内容"), MB_OKCANCEL);
break;
}
//case WM_KEYDOWN:
//{
// //判断0x14(capslk)键是否按下
// if (GetKeyState(0x14) < 0)//如果是 < 0 那证明按键被按下了
// {
// MessageBox(hwnd, TEXT("你按下了大写按键"), TEXT("消息!"), MB_OK);
// return 0;
// }
// TCHAR sZ[0X255] = { 0 };
// wsprintf(sZ, TEXT("%c"), wParam); //windows 当中的输入功能
// MessageBox(hwnd, sZ, TEXT("输入内容"), MB_OKCANCEL);
// break;
//}
//点击关闭窗口会发送WM_CLOSE消息
case WM_CLOSE:
{
int nRet = MessageBox(hwnd, TEXT("是否退出"), TEXT("询问"), MB_OKCANCEL);
if (nRet == IDCANCEL)//取消关闭
{
return 0;
}
else
{
//摧毁窗口发送WM_DESTROY消息
DestroyWindow(hwnd);
}
break;
}
// 鼠标消息,左键按下
case WM_LBUTTONDOWN:
{
int xPos = LOWORD(lParam);
int yPos = HIWORD(lParam);
//产生无效区
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
break;
}
case WM_DESTROY:
{
//向消息队列投递WM_QUIT消息 WM_QUIT使消息循环退出,程序退出。
PostQuitMessage(0);
break;
}
default:
break;
}
//系统默认处理消息窗口函数
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW; //默认风格,窗口尺寸被修改后重画窗口
wc.lpfnWndProc = MyWindowPro; //窗口回调,处理消息的(Windows消息处理用的是回调函数处理消息的,因为windows知道消息什么时候来并不知道怎么处理,所以通过回调去处理)
wc.cbClsExtra = 0; //窗口类的额外空间
wc.cbWndExtra = 0; //窗口实例的额外空间
wc.hInstance = hInstance;
wc.hIcon = NULL; //图标
wc.hCursor = NULL; //光标
wc.hbrBackground = NULL;//背景
wc.lpszMenuName = NULL;//菜单
wc.lpszClassName = TEXT("MyWindow");
ATOM nRet = RegisterClass(&wc);
return nRet;
}
HWND MyCreatWindow(HINSTANCE hInstance)
{
//创建窗口实例
HWND hWnd = CreateWindow(
TEXT("MyWindow"), //窗口类名
TEXT("Hello World"), //窗口标题
WS_OVERLAPPEDWINDOW, //重叠窗口
CW_USEDEFAULT, CW_USEDEFAULT, //默认坐标
CW_USEDEFAULT, CW_USEDEFAULT,//默认长和宽
NULL, //没有父窗口
NULL, //没有菜单
hInstance,//main函数的实例句柄
NULL//暂时不用,(LPVOID)0x87654093,可用来做参数标记
);
//显示窗口
ShowWindow(hWnd, SW_SHOW);
//更新窗口
UpdateWindow(hWnd);
return hWnd;
}
//句柄可以理解为标识ID,如窗口句柄就表示这个标识这个窗口的唯一ID
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,//应用程序当前实例的句柄
_In_opt_ HINSTANCE hPrevInstance,//应用程序的先前实例的句柄
_In_ LPTSTR lpCmdLine,//指向应用程序命令行的字符串的指针
_In_ int nCmdShow)//指明窗口如何显示,查msdn帮助文档,有各种宏
{
ATOM nRet = MyRegisterClass(hInstance);
if (nRet == 0)
{
ShowErrorMessage();
}
HWND hWnd = MyCreatWindow(hInstance);
if (hWnd == NULL)
{
ShowErrorMessage();
}
MSG msg;
//获取消息
while (GetMessage(&msg, NULL, 0, 0) != 0)
{
//keydow消息和char消息不需要都实现,不然只会进入keydown消息
//将keydown消息转换为字符消息
TranslateMessage(&msg);
//派发消息到对应的窗口过程函数
DispatchMessage(&msg);
}
return 0;
}