首頁  >  文章  >  運維  >  Win32 SDK基礎(十二)之WM_PAINT訊息的處理(圖)

Win32 SDK基礎(十二)之WM_PAINT訊息的處理(圖)

黄舟
黄舟原創
2017-06-06 10:11:467778瀏覽

一、引言

        在電腦中,螢幕上顯示的一切東西幾乎都是繪製的,包括視窗、對話方塊、圖片、以及所有文字,而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訊息,此時會列印上述字串:


2、用滑鼠調整視窗的大小,時會連續觸發:

        由於調整視窗大小時,需要不斷的重繪窗口,所以此時表現出來的就是不斷的觸發WM_PAINT訊息:


3、最小化時不會觸發WM_PAINT訊息,但從最小化還原時會進行觸發

#        下面這張圖,是在兩次從最小化到還原視窗的過程,可以看到多了兩次字串的列印


4、最大化時會觸發WM_PAINT訊息

        當圖片最大化和還原後分別觸發一次WM_PAINT訊息,如下圖所示:


#5、當向螢幕外拖曳視窗時,不會觸發WM_PAINT訊息,但拉回螢幕內時會不斷的觸發WM_PAINT訊息

        下面的截圖,就是將視窗拉回螢幕時,視窗會在不斷的進行重繪,觸發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消息。

总结:

        触发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訊息的處理(圖)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn