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

一、引言

? ? ? ? 在計算機中,屏幕上顯示的一切東西幾乎都是繪制的,包括窗口、對話框、圖片、以及一切文字,而wm_paint消息就是在繪制這些圖片時,系統觸發的消息。我們在計算機中的每一個操作,幾乎都會觸發這個消息,它也是windows中最重要的消息之一。本文主要針對該消息進行試驗,以進行全面的學習。

二、WM_PAINT基礎

?2.1 宏定義

#define?WM_PAINT????????????????????????  0x000F

2.2 攜帶參數

? ? ? ? 我們知道,在使用s圖片message/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_PAINn",10,NULL,NULL);  		}  		break;  	default:??  		break;??  	}??  	return?DefWindowProc(hWnd,?uMsg,?wParam,?lParam);??  }

? ? ? ? 我們WM_PAINT的處理語句中,向控制臺的標準輸出,寫入了一個”WM_PAINTn”的圖片,以此來驗證觸發了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、使用Inval圖片Rect函數觸發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_PAINn",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消息的處理(圖)

? 版權聲明
THE END
喜歡就支持一下吧
點贊11 分享