一、引言
在電腦中,螢幕上顯示的一切東西幾乎都是繪製的,包括視窗、對話方塊、圖片、以及所有文字,而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中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

WebStorm Mac版
好用的JavaScript開發工具

Dreamweaver CS6
視覺化網頁開發工具

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

Safe Exam Browser
Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。