1.绘图消息
WM_PAINT - 当窗口需要绘制的时候,会发送窗口处理函数。
需要重新绘制的情况:
(1)窗口从创建到第一次显示
(2)从被遮挡到重新显示
(3)窗口变大(窗口变小时,窗口本身不需要重新,但如果注册窗口类中加了CS_HREDRAW | CS_VREDRAW风格,就会重绘)
(4)调用InvalidateRect函数
窗口无效区域 - 被声明成需要重新绘制的区域。
BOOL InvalidateRect( HWND hWnd, //窗口句柄
CONST RECT* lpRect, //区域的矩形坐标
BOOL bErase); //重回前是否擦除
在程序中,如果需要绘制窗口,调用函数声明窗口无效区域。
wPARAM - 不使用
lPARAM - 不使用
消息处理步骤
(1)开始绘图处理
HDC BeginPaint( HWND hWnd, //绘图窗口
LPPAINTSTRUCT lpPaint); //绘图参数的buffer
返回绘图设备句柄HDC
(2)绘图
(3)结束绘图
BOOL EndPaint( HWND hWnd, //绘图窗口
CONST PAINTSTRUCT *lpPaint); //绘图参数的指针
2.键盘消息
WM_KEYDOWN - 按键被按下时产生
WM_KEYUP - 按键被放开时产生
WM_SYSKEYDOWN - 系统键按下时产生,比如ALT、F10
WM_SYSKEYUP - 系统键放开时产生
WM_CHAR - 字符消息(TranslateMessage发送的)
消息参数:
按键消息:wPARAM - 按键的Virtual Key(虚拟键码)(无法区分大小写,所以可见字符需要翻译)
lPARAM - 按键的参数,比如按下次数
WM_CHAR消息:wPARAM - 输入的字符(ASC字符编码)
lPARAM - 按键的相关参数
TranslateMessage(&nMsg)内部的大致处理过程:
{
检查是否是键盘消息
if ( nMsg.message != WM_KEYDOWN ) { return ; }
else
{
通过nMsg.wParam(虚拟键码)可以判断是否是可见字符的按键被按下
if (不是) { return ; }
else
{
判断CapsLock(大写锁定键是否处于打开状态)
if (关闭) { PostMessage(nMsg.hWnd, WM_CHAR, 小写字母ASC码, ...); }
else { PostMessage(nMsg.hWnd, WM_CHAR, 大写字母ASC码, ...); }
}
}
}
消息的使用
(1)KEYDOWN可以重复出现,KEYUP只能在按键松开时出现一次。
(2)TranslateMessage在转换WM_KEYDOWN消息时,对于可见字符产生WM_CHAR,不可见字符无此消息。
(3)WM_KEYDOWN/UP的wParam表示按键的虚拟键码值,WM_CHAR的wParam表示字符的ASC编码值。
下面是相关代码:
#include "stdafx.h" #include <stdio.h> HINSTANCE g_hInstance = 0; //接收当前程序实例句柄 HANDLE g_hOutput = 0; //接收标准输出句柄 void OnPaint(HWND hWnd) { char szText[] = "WM_PAINT "; //WriteConsole(g_hOutput, szText, strlen(szText), NULL, NULL); /*****************绘图********************/ PAINTSTRUCT ps = { 0 }; HDC hdc = BeginPaint(hWnd, &ps); TextOut(hdc, 100, 100, "hello", strlen("hello")); EndPaint(hWnd, &ps); /*******必须放在WM_PAINT的消息处理调用中*****/ } void OnKeyDown(HWND hWnd, WPARAM wParam) { char szText[256] = { 0 }; sprintf_s(szText, "WM_KEYDOWN:%08x ", wParam); WriteConsole(g_hOutput, szText, strlen(szText), NULL, NULL); } void OnKeyUp(HWND hWnd, WPARAM wParam) { char szText[256] = { 0 }; sprintf_s(szText, "WM_KEYUP:%08x ", wParam); WriteConsole(g_hOutput, szText, strlen(szText), NULL, NULL); } void OnChar(HWND hWnd, WPARAM wParam) { char szText[256] = { 0 }; sprintf_s(szText, "WM_CHAR:%08x ", wParam); WriteConsole(g_hOutput, szText, strlen(szText), NULL, NULL); } //窗口处理函数 LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_CHAR: OnChar(hWnd, wParam); break; case WM_KEYDOWN: OnKeyDown(hWnd, wParam); break; case WM_KEYUP: OnKeyUp(hWnd, wParam); break; case WM_LBUTTONDOWN: InvalidateRect(hWnd, NULL, TRUE); break; case WM_PAINT: OnPaint(hWnd); break; case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hWnd, msg, wParam, lParam); } //注册窗口类 BOOL Register(LPSTR lpClassName, WNDPROC wndProc) { WNDCLASSEX wce = { 0 }; wce.cbSize = sizeof(wce); wce.cbClsExtra = 200; wce.cbClsExtra = 200; wce.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wce.hCursor = NULL; wce.hIcon = NULL; wce.hIconSm = NULL; wce.hInstance = g_hInstance; wce.lpfnWndProc = wndProc; wce.lpszClassName = lpClassName; wce.lpszMenuName = NULL; wce.style = CS_HREDRAW | CS_VREDRAW; //窗口水平或垂直发生变化时,重新绘制 ATOM nAtom = RegisterClassEx(&wce); if (0 == nAtom) { return FALSE; } return TRUE; } //创建主窗口 HWND CreateMainWindow(LPSTR lpClassName, LPSTR lpWndName) { HWND hWnd = CreateWindowEx(0, lpClassName, lpWndName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, g_hInstance, NULL); return hWnd; }//显示窗口 void Display(HWND hWnd) { ShowWindow(hWnd, SW_SHOW); UpdateWindow(hWnd); } //消息循环 void Message() { MSG nMsg = { 0 }; while (GetMessage(&nMsg, NULL, 0, 0)) { TranslateMessage(&nMsg); DispatchMessage(&nMsg); } } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { AllocConsole(); g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE); g_hInstance = hInstance; Register("Main", WndProc); HWND hWnd = CreateMainWindow("Main", "window"); Display(hWnd); Message(); return 0; }