06 Windows编程——设备句柄 和 WM_PAINT消息
windows程序在现实方式上属于图形方式,和文字方式的显示,有显著的不同。
什么是设备句柄,如何获取
使用统一的数据结构表示某一设备,这个结构就是设备句柄。

源码
#include<Windows.h> LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); int WinMain(HINSTANCE hInst, HINSTANCE tmp, LPSTR szCmd, int nShow)
{
WNDCLASS WndClass;
TCHAR* ClassName = TEXT("MyClass");
HWND hwnd;
MSG msg; WndClass.cbClsExtra = ;
WndClass.cbWndExtra = ;
WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + );
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hInstance = hInst;
WndClass.lpfnWndProc = WindProc;
WndClass.lpszClassName = ClassName;
WndClass.lpszMenuName = NULL;
WndClass.style = CS_VREDRAW | CS_HREDRAW; if (!RegisterClass(&WndClass))
{
MessageBox(NULL, TEXT("Gegister Class Fail!!"), TEXT("error"), MB_OK);
return ;
} hwnd = CreateWindow(ClassName, TEXT("Hello"), WS_OVERLAPPEDWINDOW, , , CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL);
if (hwnd == NULL)
{
MessageBox(NULL, TEXT("Create Window Fail!!"), TEXT("error"), MB_OK);
return ;
}
ShowWindow(hwnd, nShow);
UpdateWindow(hwnd); while (GetMessage(&msg,NULL,,))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} return ;
} LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT pt;
TCHAR* str = TEXT("hello");
switch (message)
{
case WM_DESTROY:
PostQuitMessage();//发送WM_QUIT消息
return ;
case WM_PAINT:
hdc = BeginPaint(hwnd, &pt);
TextOut(hdc, , , str, _tcslen(str));
EndPaint(hwnd, &pt);
return ;
default:
break;
} return DefWindowProc(hwnd, message, wParam, lParam);
}
对WM_PAINT消息的处理几乎总是从调用BeginPaint函数开始:hdc = BeginPaint(hwnd, &pt)
而以调用EndPaint函数结束:EndPaint(hwnd, &pt);
在这两个函数调用中,第一个参数均为程序的窗口句柄,而第二个参数均为指向一个类型为PAINTSTRUCT结构的指针。PAINTSTRUCT结构包含一些窗口过程用来对客户区进行绘制的信息。
BeginPaint 调用将使整个客户区有效,并返回一个“设备环境句柄”。
如何知道客户区呢?
该函数的第一个参数是程序的窗口句柄。第二个参数为指向类型为RECT的矩形结构的指针。该结构具有4个类型为LONG的字段,名称分别为left、top、right 和botom。GetclientRect函数将依据窗口尺寸来对这4个字段进行设置。其中,left和top字段总是会被赋为0,这样right和bottom字段就分别表示以像素为单位的客户区的宽度和高度。
BOOL GetClientRect(
HWND hWnd, // 窗口句柄
LPRECT lpRect // 客户区坐标
);
也可以这样
#include<Windows.h> LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); int WinMain(HINSTANCE hInst, HINSTANCE tmp, LPSTR szCmd, int nShow)
{
WNDCLASS WndClass;
TCHAR* ClassName = TEXT("MyClass");
HWND hwnd;
MSG msg; WndClass.cbClsExtra = ;
WndClass.cbWndExtra = ;
WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + );
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hInstance = hInst;
WndClass.lpfnWndProc = WindProc;
WndClass.lpszClassName = ClassName;
WndClass.lpszMenuName = NULL;
WndClass.style = CS_VREDRAW | CS_HREDRAW; if (!RegisterClass(&WndClass))
{
MessageBox(NULL, TEXT("Gegister Class Fail!!"), TEXT("error"), MB_OK);
return ;
} hwnd = CreateWindow(ClassName, TEXT("Hello"), WS_OVERLAPPEDWINDOW, , , CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL);
if (hwnd == NULL)
{
MessageBox(NULL, TEXT("Create Window Fail!!"), TEXT("error"), MB_OK);
return ;
}
ShowWindow(hwnd, nShow);
UpdateWindow(hwnd); while (GetMessage(&msg,NULL,,))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} return ;
} LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT pt;
TCHAR* str = TEXT("hello");
switch (message)
{
case WM_DESTROY:
PostQuitMessage();//发送WM_QUIT消息
return ;
case WM_PAINT:
/*hdc = BeginPaint(hwnd, &pt);
TextOut(hdc, 0, 0, str, _tcslen(str));
EndPaint(hwnd, &pt);*/
hdc = GetDC(hwnd);
TextOut(hdc, , , str, _tcslen(str));
ReleaseDC(hwnd, hdc);
ValidateRect(hwnd, NULL);
return ;
default:
break;
} return DefWindowProc(hwnd, message, wParam, lParam);
}
使用EndPaint,直接就会使pt指向的区域变成有效区域。而ReleaseDC不会,WM_PAINT会一直存在,需要手动调用函数ValidateRect释放无效区。使无效客户区有效。
第三种做法
#include<Windows.h> LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); int WinMain(HINSTANCE hInst, HINSTANCE tmp, LPSTR szCmd, int nShow)
{
WNDCLASS WndClass;
TCHAR* ClassName = TEXT("MyClass");
HWND hwnd;
MSG msg; WndClass.cbClsExtra = ;
WndClass.cbWndExtra = ;
WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + );
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hInstance = hInst;
WndClass.lpfnWndProc = WindProc;
WndClass.lpszClassName = ClassName;
WndClass.lpszMenuName = NULL;
WndClass.style = CS_VREDRAW | CS_HREDRAW; if (!RegisterClass(&WndClass))
{
MessageBox(NULL, TEXT("Gegister Class Fail!!"), TEXT("error"), MB_OK);
return ;
} hwnd = CreateWindow(ClassName, TEXT("Hello"), WS_OVERLAPPEDWINDOW, , , CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL);
if (hwnd == NULL)
{
MessageBox(NULL, TEXT("Create Window Fail!!"), TEXT("error"), MB_OK);
return ;
}
ShowWindow(hwnd, nShow);
UpdateWindow(hwnd); while (GetMessage(&msg,NULL,,))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} return ;
} LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT pt;
TCHAR* str = TEXT("hello");
switch (message)
{
case WM_DESTROY:
PostQuitMessage();//发送WM_QUIT消息
return ;
case WM_PAINT:
/* 第一种
hdc = BeginPaint(hwnd, &pt);
TextOut(hdc, 0, 0, str, _tcslen(str));
EndPaint(hwnd, &pt);
*/ /* 第二种
hdc = GetDC(hwnd);
TextOut(hdc, 0, 0, str, _tcslen(str));
ReleaseDC(hwnd, hdc);
ValidateRect(hwnd, NULL);
*/ hdc = GetWindowDC(hwnd);
TextOut(hdc, , , str, _tcslen(str));
ReleaseDC(hwnd, hdc);
ValidateRect(hwnd, NULL);
return ;
default:
break;
} return DefWindowProc(hwnd, message, wParam, lParam);
}
GetWindowDC、ReleaseDC操作窗口句柄,在绘制时不是以有效区作为参考,而是以整个窗口做参考,所以需要在TextOut里面调整输出文字的位置
代码里TextOut只在pt这个无效区显示输出文字。
HDC BeginPaint( HWND hWnd, LPPAINTSTRUCT lpPaint ); hWnd:窗口句柄 lpPaint:包含了用来重画客户区的程序信息
typedef struct tagPAINTSTRUCT {
HDC hdc; //用来在客户去画图的设备表
BOOL fErase; //客户背景区是否需要重绘(stru=是)
RECT rcPaint; //无效客户区
BOOL fRestore; //保留
BOOL fIncUpdate;//保留
BYTE rgbReserved[];//保留
} PAINTSTRUCT;
前面3段代码主要围绕设备句柄处理WM_PAINT消息。
如果使用TextOut在输出一段文字,调整不好位置的话容易遮挡之前输出的文字。代码如下
#include<Windows.h> LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); int WinMain(HINSTANCE hInst, HINSTANCE tmp, LPSTR szCmd, int nShow)
{
WNDCLASS WndClass;
TCHAR* ClassName = TEXT("MyClass");
HWND hwnd;
MSG msg; WndClass.cbClsExtra = ;
WndClass.cbWndExtra = ;
WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + );
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hInstance = hInst;
WndClass.lpfnWndProc = WindProc;
WndClass.lpszClassName = ClassName;
WndClass.lpszMenuName = NULL;
WndClass.style = CS_VREDRAW | CS_HREDRAW; if (!RegisterClass(&WndClass))
{
MessageBox(NULL, TEXT("Gegister Class Fail!!"), TEXT("error"), MB_OK);
return ;
} hwnd = CreateWindow(ClassName, TEXT("Hello"), WS_OVERLAPPEDWINDOW, , , CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL);
if (hwnd == NULL)
{
MessageBox(NULL, TEXT("Create Window Fail!!"), TEXT("error"), MB_OK);
return ;
}
ShowWindow(hwnd, nShow);
UpdateWindow(hwnd); while (GetMessage(&msg,NULL,,))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} return ;
} LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT pt;
TCHAR* str = TEXT("hello");
TCHAR* str1 = TEXT("World");
switch (message)
{
case WM_DESTROY:
PostQuitMessage();//发送WM_QUIT消息
return ;
case WM_PAINT:
hdc = BeginPaint(hwnd, &pt);
TextOut(hdc, , , str, _tcslen(str));
TextOut(hdc, , , str1, _tcslen(str1));
EndPaint(hwnd, &pt); /* 第二种
hdc = GetDC(hwnd);
TextOut(hdc, 0, 0, str, _tcslen(str));
ReleaseDC(hwnd, hdc);
ValidateRect(hwnd, NULL);
*/ /* 第三种
hdc = GetWindowDC(hwnd);
TextOut(hdc, 100, 100, str, _tcslen(str));
ReleaseDC(hwnd, hdc);
ValidateRect(hwnd, NULL);
*/ return ;
default:
break;
} return DefWindowProc(hwnd, message, wParam, lParam);
}
输出结果


获得字体高度的函数:BOOL GetTextMetrics( HDC hdc, LPTEXTMETRIC lptm );
#include<Windows.h> LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); int WinMain(HINSTANCE hInst, HINSTANCE tmp, LPSTR szCmd, int nShow)
{
WNDCLASS WndClass;
TCHAR* ClassName = TEXT("MyClass");
HWND hwnd;
MSG msg; WndClass.cbClsExtra = ;
WndClass.cbWndExtra = ;
WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + );
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hInstance = hInst;
WndClass.lpfnWndProc = WindProc;
WndClass.lpszClassName = ClassName;
WndClass.lpszMenuName = NULL;
WndClass.style = CS_VREDRAW | CS_HREDRAW; if (!RegisterClass(&WndClass))
{
MessageBox(NULL, TEXT("Gegister Class Fail!!"), TEXT("error"), MB_OK);
return ;
} hwnd = CreateWindow(ClassName, TEXT("Hello"), WS_OVERLAPPEDWINDOW, , , CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL);
if (hwnd == NULL)
{
MessageBox(NULL, TEXT("Create Window Fail!!"), TEXT("error"), MB_OK);
return ;
}
ShowWindow(hwnd, nShow);
UpdateWindow(hwnd); while (GetMessage(&msg,NULL,,))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} return ;
} LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT pt;
TEXTMETRIC ts;
TCHAR* str = TEXT("hello");
TCHAR* str1 = TEXT("World");
switch (message)
{
case WM_DESTROY:
PostQuitMessage();//发送WM_QUIT消息
return ;
case WM_PAINT:
hdc = BeginPaint(hwnd, &pt);
TextOut(hdc, , , str, _tcslen(str));
GetTextMetrics(hdc, &ts);
TextOut(hdc, , ts.tmHeight, str1, _tcslen(str1));
EndPaint(hwnd, &pt); /* 第二种
hdc = GetDC(hwnd);
TextOut(hdc, 0, 0, str, _tcslen(str));
ReleaseDC(hwnd, hdc);
ValidateRect(hwnd, NULL);
*/ /* 第三种
hdc = GetWindowDC(hwnd);
TextOut(hdc, 100, 100, str, _tcslen(str));
ReleaseDC(hwnd, hdc);
ValidateRect(hwnd, NULL);
*/ return ;
default:
break;
} return DefWindowProc(hwnd, message, wParam, lParam);
}
前面讲到3中获取hdc的方式,第一种 BeginPaint & EndPaint,在EndPaint之后,原来的无效区就成为有效区,不在发送WM_PAINT重绘
而第二三种方法,在ReleaseDC后,并不能使原来的无效区成为有效区,一直是无效区。需要使用ValidateRect(hwnd, NULL);来使原来的无效区变成有效区,但是这种方法效率太低,是整个窗口的重回。可以先获取窗口无效区,在针对这个无效区进行重绘
BOOL ValidateRect(
HWND hWnd, // 窗口的句柄
CONST RECT *lpRect // 指向RECT结构的指针
);
也就是代码顺序
GetUpdateRect
ValidateRect //让某一个矩形区域变得有效
如果只用第一种方法,就不必写上面2个函数了。
获取窗口无效区域: BOOL GetUpdateRect( HWND hWnd, LPRECT lpRect, BOOL bErase );
bErase :如果不想擦除背景,这个值就为false.
BOOL GetUpdateRect(
HWND hWnd,
LPRECT lpRect,
BOOL bErase
);
改变hdc设备句柄中字体颜色
COLORREF SetTextColor( HDC hdc, COLORREF color );
#include<Windows.h> LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); int WinMain(HINSTANCE hInst, HINSTANCE tmp, LPSTR szCmd, int nShow)
{
WNDCLASS WndClass;
TCHAR* ClassName = TEXT("MyClass");
HWND hwnd;
MSG msg; WndClass.cbClsExtra = ;
WndClass.cbWndExtra = ;
WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + );
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hInstance = hInst;
WndClass.lpfnWndProc = WindProc;
WndClass.lpszClassName = ClassName;
WndClass.lpszMenuName = NULL;
WndClass.style = CS_VREDRAW | CS_HREDRAW; if (!RegisterClass(&WndClass))
{
MessageBox(NULL, TEXT("Gegister Class Fail!!"), TEXT("error"), MB_OK);
return ;
} hwnd = CreateWindow(ClassName, TEXT("Hello"), WS_OVERLAPPEDWINDOW, , , CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL);
if (hwnd == NULL)
{
MessageBox(NULL, TEXT("Create Window Fail!!"), TEXT("error"), MB_OK);
return ;
}
ShowWindow(hwnd, nShow);
UpdateWindow(hwnd); while (GetMessage(&msg,NULL,,))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} return ;
} LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT pt;
TEXTMETRIC ts;
TCHAR* str = TEXT("hello");
TCHAR* str1 = TEXT("World");
switch (message)
{
case WM_DESTROY:
PostQuitMessage();//发送WM_QUIT消息
return ;
case WM_PAINT:
hdc = BeginPaint(hwnd, &pt);
SetTextColor(hdc, RGB(0x0, 0xFF, ));
TextOut(hdc, , , str, _tcslen(str));
GetTextMetrics(hdc, &ts);
TextOut(hdc, , ts.tmHeight, str1, _tcslen(str1));
EndPaint(hwnd, &pt); /* 第二种
hdc = GetDC(hwnd);
TextOut(hdc, 0, 0, str, _tcslen(str));
ReleaseDC(hwnd, hdc);
ValidateRect(hwnd, NULL);
*/ /* 第三种
hdc = GetWindowDC(hwnd);
TextOut(hdc, 100, 100, str, _tcslen(str));
ReleaseDC(hwnd, hdc);
ValidateRect(hwnd, NULL);
*/ return ;
default:
break;
} return DefWindowProc(hwnd, message, wParam, lParam);
}
可以在Win10上选好颜色,然后初始化RGB
桌面->右键->个性化->颜色->自定义颜色

创建画刷函数
HBRUSH CreateSolidBrush( COLORREF color );
#include<Windows.h>
#include<tchar.h>
#define NUM 1000 LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); int WinMain(HINSTANCE hInst, HINSTANCE tmp, LPSTR szCmd, int nShow)
{
WNDCLASS WndClass;
TCHAR* ClassName = TEXT("MyClass");
HWND hwnd;
MSG msg;
HBRUSH hBrush;
hBrush = CreateSolidBrush(RGB(0xFF, , )); WndClass.cbClsExtra = ;
WndClass.cbWndExtra = ;
WndClass.hbrBackground = hBrush;
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hInstance = hInst;
WndClass.lpfnWndProc = WindProc;
WndClass.lpszClassName = ClassName;
WndClass.lpszMenuName = NULL;
WndClass.style = CS_VREDRAW | CS_HREDRAW; if (!RegisterClass(&WndClass))
{
MessageBox(NULL, TEXT("Gegister Class Fail!!"), TEXT("error"), MB_OK);
return ;
} hwnd = CreateWindow(ClassName, TEXT("Hello"), WS_OVERLAPPEDWINDOW, , , , , NULL, NULL, hInst, NULL);
if (hwnd == NULL)
{
MessageBox(NULL, TEXT("Create Window Fail!!"), TEXT("error"), MB_OK);
return ;
}
ShowWindow(hwnd, nShow);
UpdateWindow(hwnd); while (GetMessage(&msg, NULL, , ))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} return ;
} LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT pt;
TEXTMETRIC ts;
TCHAR* str = TEXT("hello");
TCHAR* str1 = TEXT("World");
switch (message)
{
case WM_DESTROY:
PostQuitMessage();//发送WM_QUIT消息
return ;
case WM_PAINT:
hdc = BeginPaint(hwnd, &pt);
SetTextColor(hdc, RGB(0x0, 0xFF, ));
TextOut(hdc, , , str, _tcslen(str));
GetTextMetrics(hdc, &ts);
TextOut(hdc, , ts.tmHeight, str1, _tcslen(str1));
EndPaint(hwnd, &pt); /* 第二种
hdc = GetDC(hwnd);
TextOut(hdc, 0, 0, str, _tcslen(str));
ReleaseDC(hwnd, hdc);
ValidateRect(hwnd, NULL);
*/ /* 第三种
hdc = GetWindowDC(hwnd);
TextOut(hdc, 100, 100, str, _tcslen(str));
ReleaseDC(hwnd, hdc);
ValidateRect(hwnd, NULL);
*/ return ;
default:
break;
} return DefWindowProc(hwnd, message, wParam, lParam);
}
改变字体大小
#include<Windows.h> LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); int WinMain(HINSTANCE hInst, HINSTANCE tmp, LPSTR szCmd, int nShow)
{
WNDCLASS WndClass;
TCHAR* ClassName = TEXT("MyClass");
HWND hwnd;
MSG msg; WndClass.cbClsExtra = ;
WndClass.cbWndExtra = ;
WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + );
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hInstance = hInst;
WndClass.lpfnWndProc = WindProc;
WndClass.lpszClassName = ClassName;
WndClass.lpszMenuName = NULL;
WndClass.style = CS_VREDRAW | CS_HREDRAW; if (!RegisterClass(&WndClass))
{
MessageBox(NULL, TEXT("Gegister Class Fail!!"), TEXT("error"), MB_OK);
return ;
} hwnd = CreateWindow(ClassName, TEXT("Hello"), WS_OVERLAPPEDWINDOW, , , CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL);
if (hwnd == NULL)
{
MessageBox(NULL, TEXT("Create Window Fail!!"), TEXT("error"), MB_OK);
return ;
}
ShowWindow(hwnd, nShow);
UpdateWindow(hwnd); while (GetMessage(&msg, NULL, , ))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} return ;
} LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
TEXTMETRIC ts;
TCHAR* str1 = TEXT("World");
HDC hdc;
PAINTSTRUCT pt;
TCHAR* str = TEXT("hello");
HFONT hFont;
hFont = CreateFont(, , , , , , , , , , , , , NULL);
switch (message)
{
case WM_DESTROY:
PostQuitMessage();//发送WM_QUIT消息
return ;
case WM_PAINT:
hdc = BeginPaint(hwnd, &pt);
SelectObject(hdc, hFont);
SetTextColor(hdc, RGB(0x0, 0xFF, ));
TextOut(hdc, , , str, _tcslen(str));
GetTextMetrics(hdc, &ts);
TextOut(hdc, , ts.tmHeight, str1, _tcslen(str1));
EndPaint(hwnd, &pt); /* 第二种
hdc = GetDC(hwnd);
TextOut(hdc, 0, 0, str, _tcslen(str));
ReleaseDC(hwnd, hdc);
ValidateRect(hwnd, NULL);
*/ /* 第三种
hdc = GetWindowDC(hwnd);
TextOut(hdc, 100, 100, str, _tcslen(str));
ReleaseDC(hwnd, hdc);
ValidateRect(hwnd, NULL);
*/ return ;
default:
break;
} return DefWindowProc(hwnd, message, wParam, lParam);
}
WM_PAINT消息的来源和处理方式
客户区:客户区是一块应用程序可以自由绘图并向用户传达可视输出的区域。
WM_PAINT何时产生?
当窗口的客户区的部分或全部“无效”且必须“更新”时,应用程序将得到此通知。这也就意味着窗口必须被“重绘”。
何种情况下客户区会变为无效?
①当窗口被首次创建时,整个客户区都是无效的,因为此时应用程序尚未在该窗口上绘制任何东西。第一条WM_PAINT消息(通常在应用程序调用WinMain中的UpdateWindow时出现)将指示窗口过程在窗口客户区进行绘制。
②在调整窗口的尺寸时,客户区也会变为无效。你可能还记得在前面的程序中,我们将窗口类结构的style字段设为了标记CS_HREDRAW和CSVREDRAW。这就指示Windows当窗口尺寸发生变化时,整个窗口都应宣布无效。在此之后,窗口过程将接收到一条WM_PAINT消息。
③如果先最小化窗口,然后再将窗口恢复到原先的尺寸,Windows并不会保存客户区的内容。在图形环境中,这种情况下需要保存的数据太多了。对此,Windows采取的策略是宣布窗口无效。窗口过程接收到WM_PAINT消息后,会自行恢复窗口的内容。
④在屏幕中拖动窗口导致窗口之间发生重叠时,Windows并不负责保存被另一个窗口覆盖的区域。当被覆盖的区域在后来不再被遮挡时,窗口被标记为无效。窗口过程会收到一条WM_PAINT消息,并对窗口的内容进行重绘。
例外情况?
鼠标滑过窗口,此时不发送WM_PAINT消息。这个重绘,由系统完成。
强制窗口重绘的函数:InvalidateRect和InvalidateRgn。
强制制定某一区域无效,需要重绘
BOOL InvalidateRect(HWND hWnd, CONST RECT *lpRect, BOOL bErase);
hWnd:想让哪个窗口的客户区无效
lpRect:客户无效区域
bErase:窗口背景是否需要重新绘制,如果是TRUE,那么窗口背景被擦去,需要重新绘制。
BOOL InvalidateRgn( HWND hWnd, HRGN hRgn, BOOL bErase );
hWnd:想让哪个窗口的客户区无效
hRgn:客户无效区域
bErase:窗口背景是否需要重新绘制,如果是TRUE,那么窗口背景被擦去,需要重新绘制。
HRGN和RECT之间的相互转换:CreateRectRgnIndirect
HRGN CreateRectRgnIndirect( CONST RECT *lprect );
06 Windows编程——设备句柄 和 WM_PAINT消息的更多相关文章
- 用了WS_EX_LAYERED 后所有Twincontrl的wm_paint消息会停止(官方Layered Windows文档很多内容)good
fmx 和 vcl 不一样, fmx 的阴影可以通过2D显示出来. VCL 无标题栏窗口的阴影很麻烦 280425268 我也是用两个窗口做阴影,并重绘了非客户区,不过阴影是基础自TwinContro ...
- windows 编程 —— 消息与参数(滚动条、键盘、鼠标)
目录: 滚动条 键盘 鼠标 滚动条ScrollBar 发送消息:WM_VSCROLL和WM_HSCROLL 参数wParam:wParam消息参数被分为一个低字组和一个高字组.wParam的低字组是一 ...
- windows编程,消息函数中拦截消息的问题
很多年没有写windows窗口程序了,今天自制基于vulkan的程序时遇到了一些问题,部分代码如下: LRESULT CALLBACK XWindow::WndProc(HWND hWnd, UINT ...
- 【Windows编程】系列第三篇:文本字符输出
上一篇我们展示了如何使用Windows SDK创建基本控件,本篇来讨论如何输出文本字符. 在使用Win32编程时,我们常常要输出文本到窗口上,Windows所有的文本字符或者图形输出都是通过图形设备接 ...
- Windows编程 Windows程序的生与死(上)
引子 “Windows 程序分为‘程序代码’和‘UI(User Interface)资源’两大部份,两部份最后以RC编译器(资源编译器)整合为一个完整的EXE 文件.所谓UI 资源是指功能菜单.对话框 ...
- 【Windows编程】系列第十篇:文本插入符
大家知道,在使用微软的编程环境创建工程时会让你选择是控制台模式还是Windows应用程序.如果选择控制台的console模式,就会在运行时出现一个黑洞洞的字符模式窗口,里面就有等待输入一闪一闪的插入符 ...
- 【Windows编程】系列第五篇:GDI图形绘制
上两篇我们学习了文本字符输出以及Unicode编写程序,知道如何用常见Win32输出文本字符串,这一篇我们来学习Windows编程中另一个非常重要的部分GDI图形绘图.Windows的GDI函数包含数 ...
- 【Windows编程】系列第九篇:剪贴板使用
上一篇我们学习了常见的通用对话框,本篇来了解剪贴板的使用,它常用于复制粘贴功能. 剪贴板是Windows最早就加入的功能,由于该功能非常实用,我们几乎每天都会使用到.通过剪贴板,我们就可以将数据从一个 ...
- Windows编程入门程序详解
引用:http://blog.csdn.net/jarvischu/article/details/8115390 1. 程序 /******************************* ...
随机推荐
- Python3之返回函数
参考:https://www.cnblogs.com/mzc1997/p/7641995.html Python中函数不仅可以作为参数还可以作为结果返回 >>> def pro1(c ...
- MVC模式实现注册登录
很多人对MVC模式搞不懂,刚开始是我也犯迷糊,知道看到一个前辈写的代码,我顿时有的恍然大悟,拿来分享给各位 MVC: 就是M:模型.V:视图(前台界面)C:后台处理的servlet 话不多说.上代码 ...
- WebStorm+Chrome调试Vue步骤
在调试时请 注意 : 在WebStorm中启动调试时,WebStorm会根据你设置的url,自动打开新的Chrome浏览器进程访问这个设置的url,而且这个浏览器页面和你平常看到的浏览器差异会比较大, ...
- jqGrid取消所有选中
// 获取所有选中行id var jqGridRowid=$("#jqGrid").jqGrid("getGridParam","selarrrow& ...
- 基于tesseract-OCR进行中文识别
1. 环境准备 1.1 下载 下载Tesseract-OCR安装包,地址为: https://digi.bib.uni-mannheim.de/tesseract/tesseract-ocr-w32- ...
- S1. Android 功能大全
[概述] 这篇文章主要描述安卓开发中可能实现的功能点. [准备工作] IDE:Android Studio,简单操作 如何创建一个 Android 项目 Android 项目结构分析 Androidm ...
- [tensorflow] 入门day1-数据整理与展示
tensorflow真是一个我绕不开的坑(苍天饶过谁.jpg) 其实tensorflow1和2的差别挺大的,暂时从1入坑,2的话之后简单过一下. tf2中更改的函数(供参考):https://docs ...
- Centos7.x 安装libevent2.x
1.在http://libevent.org/下载libevent-2.1.8-stable.tar.gz 2.tar -zxvf libevent-2.1.8-stable.tar.gz 3.cd ...
- Oracle数据库——ROWNUM
Oracle数据库--ROWNUM 前言 刚学到了ROWNUM的用法,网上一搜,结果发现了有很多帖子,写的都很全.本着好记性不如烂笔头的原则,我还是决定自己手打一遍,当然下面也附上了我参考的链接. ...
- go 通过赋值给 _ 来忽略序号和值
go 语言中 只要想忽略的值都需要用 下划线 _ 来代替 package main import "fmt" func main() { pow := make([]int ...