欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  运维

Win32 SDK基础(十二)之WM_PAINT消息的处理(图)

程序员文章站 2022-03-08 20:41:10
...

一、引言

在计算机中,屏幕上显示的一切东西几乎都是绘制的,包括窗口、对话框、图片、以及一切文字,而WM_PAINT消息就是在绘制这些对象时,系统触发的消息。我们在计算机中的每一个操作,几乎都会触发这个消息,它也是WIndows中最重要的消息之一。本文主要针对该消息进行试验,以进行全面的学习。

二、WM_PAINT基础

2.1 宏定义

#define WM_PAINT                        
0x000F

2.2 携带参数

我们知道,在使用sendmessage/postmessage发送消息时,往往会携带WPARAM和LPARAM两个参数,而使用GetMessage或者PeekMessage接收消息时,也会接收到这两个参数。其中部分消息,会在参数中携带一些必要信息,比如鼠标位置、窗口长度和宽度等等。WM_PAINT的这两个参数为空,没有携带消息。

2.3 触发时机

为了获取到该消息的触发时机,我们先创建一个Win32窗口项目作为试验对象。其窗口的处理函数定义如下:

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)  
{  
	switch (uMsg)  
	{  
	case WM_DESTROY:  
		PostQuitMessage(0);//可以使GetMessage返回0  
		break;
	case  WM_PAINT:
		{
			WriteConsole(hOutput,"WM_PAIN\n",10,NULL,NULL);
		}
		break;
	default:  
		break;  
	}  
	return DefWindowProc(hWnd, uMsg, wParam, lParam);  
}

我们WM_PAINT的处理语句中,向控制台的标准输出,写入了一个"WM_PAINT\n"的字符串,以此来验证触发了WM_PAINT消息。下面就WM_PAINT的触发时机分别进行验证:

1、程序启动时,绘制窗口时触发。

在我们启动程序时,由于需要绘制窗口,会触发WM_PAINT消息,此时会打印上述字符串:

Win32 SDK基础(十二)之WM_PAINT消息的处理(图)

2、用鼠标调整窗口的大小,时会连续触发:

由于调整窗口大小时,需要不断的重绘窗口,所以此时表现出来的就是不断的触发WM_PAINT消息:

Win32 SDK基础(十二)之WM_PAINT消息的处理(图)

3、最小化时不会触发WM_PAINT消息,但是从最小化还原时会进行触发

下面这张图,是在两次从最小化到还原窗口的过程,可以看到多了两次字符串的打印

Win32 SDK基础(十二)之WM_PAINT消息的处理(图)

4、最大化时会触发WM_PAINT消息

当图片最大化和还原后分别触发一次WM_PAINT消息,如下图所示:

Win32 SDK基础(十二)之WM_PAINT消息的处理(图)

5、当向屏幕外拖动窗口时,不会触发WM_PAINT消息,但是拉回到屏幕内时会不断的触发WM_PAINT消息

下面的截图,就是在将窗口拉回屏幕时,窗口在不断的进行重绘,触发着WM_PAINT消息。

Win32 SDK基础(十二)之WM_PAINT消息的处理(图)

6、使用InvalidateRect函数触发WM_PAINT消息

InvalidateRect的函数原型如下,每次调用都会触发一次WM_PAINT消息:

BOOL InvalidateRect(
HWND hWnd, // handle of window with changed update region
CONST RECT *lpRect, // address of rectangle coordinates
BOOL bErase // erase-background flag
);

hWnd:要更新的客户区所在的窗体的句柄。如果为NULL,则系统将在函数返回前重新绘制所有的窗口, 然后发送 WM_ERASEBKGND 和 WM_PAINT 给窗口过程处理函数。
lpRect:无效区域的矩形代表,它是一个结构体指针,存放着矩形的大小。如果为NULL,全部的窗口客户区域将被增加到更新区域中。
bErase:指出无效矩形被标记为有效后,是否重画该区域,重画时用预先定义好的画刷。当指定TRUE时需要重画。
返回值:
函数成功则返回非零值,否则返回零值。

为了验证InvalidateRect函数的作用,我们需要在窗口处理函数中增加一个对WM_LBUTTONDOWN消息的处理,每点击一次鼠标左键就调用一次InvalidateRect:

//窗口处理函数  
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)  
{  
	switch (uMsg)  
	{  
	case WM_DESTROY:  
		PostQuitMessage(0);//可以使GetMessage返回0  
		break;
	case  WM_PAINT:
		{
			WriteConsole(hOutput,"WM_PAIN\n",10,NULL,NULL);
		}
	case WM_LBUTTONDOWN:
		{
			InvalidateRect(hWnd,NULL,true);
		}
		break;
	default:  
		break;  
	}  
	return DefWindowProc(hWnd, uMsg, wParam, lParam);  
}

下图为执行结果,点击了3次鼠标左键,触发了3次WM_PAINT消息。

Win32 SDK基础(十二)之WM_PAINT消息的处理(图)

总结:

触发WM_PAINT消息的本质是改变窗口对应的显存的大小就触发一次,我们进行的每一次窗口最大化、最小化并恢复都是因为改变了窗口的显存而触发了该消息。在我们向屏幕外面拖动窗口时,这点比较特殊,窗口的显存是在一点点被擦除的,此时不会触发WM_PAINT,但是拉回窗口后,显存需要将擦除的部分重新绘制,这就又会触发一次该消息。而InvalidateRect函数,就是通过强制的清除并重绘显存来实现触发WM_PAINT消息。

三、WM_PAINT消息的处理

我们尝试处理WM_PAINT消息,并在窗口上绘制一个矩形,绘图步骤如下:

1、开始绘图处理

HDC BeginPaint(
        HWND hwnd,//绘图窗口
        LPPAINTSTRUCT  lpPaint
	);

我们利用BeginPaint获取绘图设备的句柄---一个HDC对象,然后在改绘图设备上进行绘制。

2、利用HDC对象进行绘图

3、结束绘图处理

Bool EndPoint(
        HWND hWnd,
        CONST PAINTSTRUCT *lpPaint
);

绘制过程参考下面的代码:

//窗口处理函数  
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)  
{  
	
	switch (uMsg)  
	{  
	case WM_DESTROY:  
		PostQuitMessage(0);//可以使GetMessage返回0  
		break;
	case  WM_PAINT:
		{
			PAINTSTRUCT pt;
			HDC hdc;
			hdc=BeginPaint(hWnd,&pt);
			Rectangle(hdc,0,0,100,100);
			EndPaint(hWnd,&pt);
		}
	case WM_LBUTTONDOWN:
		{
			//InvalidateRect(hWnd,NULL,true);
		}
		break;
	default:  
		break;  
	}  
	return DefWindowProc(hWnd, uMsg, wParam, lParam);  
}

执行结果如下,我们成功绘制了一个矩形:

Win32 SDK基础(十二)之WM_PAINT消息的处理(图)

以上就是Win32 SDK基础(十二)之WM_PAINT消息的处理(图)的详细内容,更多请关注其它相关文章!

相关标签: Win32,WM_PAINT,SDK