跟我一起玩Win32開發(3):窗口的重繪






c可以編譯
#include <Windows.h> //先聲明一下消息處理函數 LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); // 入口點 int CALLBACK WinMain( HINSTANCE hInstance, HINSTANCE hPrvInstance, LPSTR lpCommandLine, int cmdShow) { CHAR* cln = "MyApp"; //設計窗口類 WNDCLASS wc = {}; wc.hInstance = hInstance; wc.lpszClassName = cln; wc.lpfnWndProc = MyWindowProc; //注冊窗口類 RegisterClass(&wc); // 創建窗口 HWND hMainwind = CreateWindow( cln, "繪制窗口", WS_OVERLAPPEDWINDOW, 20, 12, 450, 300, NULL, NULL, hInstance, NULL); // 顯示窗口 if(hMainwind == NULL) return 0; ShowWindow(hMainwind,SW_NORMAL); // 消息循環 MSG msg; while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } // 窗口消息處理程序 LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_PAINT: break; case WM_DESTROY: PostQuitMessage(0);//退出程序 return 0; default: return DefWindowProc(hwnd,msg,wParam,lParam); } }   

上面這段是修改了char不兼容,藍色地方 寬字符

 

 

c/c++都可以編譯

#include <Windows.h>  
#include<iostream>
//先聲明一下消息處理函數  
LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

// 入口點  
int CALLBACK WinMain(
	HINSTANCE hInstance,
	HINSTANCE hPrvInstance,
	LPSTR lpCommandLine,
	int cmdShow)
{
	//PCWSTR cln = 0;
	//設計窗口類  
	WNDCLASS wc = { 0 };
	wc.hInstance = hInstance;
	wc.lpszClassName = "ewfewew";
	wc.lpfnWndProc = MyWindowProc;
	//注冊窗口類  
	RegisterClass(&wc);
	// 創建窗口  
	HWND hMainwind = CreateWindow(
		"ewfewew",
		"qwer",
		WS_OVERLAPPEDWINDOW,
		20,
		12,
		450,
		300,
		NULL,
		NULL,
		hInstance,
		NULL);
	// 顯示窗口  
	if (hMainwind == NULL)
		return 0;
	ShowWindow(hMainwind, SW_NORMAL);
	// 消息循環  
	MSG msg;
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return 0;
}

// 窗口消息處理程序  
LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
	case WM_PAINT:
		break;
	case WM_DESTROY:
		PostQuitMessage(0);//退出程序  
		return 0;
	default:
		return DefWindowProc(hwnd, msg, wParam, lParam);
	}
	
}

  

 

 

 

 

 

我們今天來吹一下關於窗口重繪的事情,在開始吹牛之前,我們先用上一篇博文中說到的方法寫一個簡單的Win32應用程序。代碼如下:

[cpp]  view plain  copy
 
  1. #include <Windows.h>  
  2.   
  3. //先聲明一下消息處理函數  
  4. LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);  
  5.   
  6. // 入口點  
  7. int CALLBACK WinMain(  
  8.     HINSTANCE hInstance,  
  9.     HINSTANCE hPrvInstance,  
  10.     LPSTR lpCommandLine,  
  11.     int cmdShow)  
  12. {  
  13.     WCHAR* cln = L"MyApp";  
  14.     //設計窗口類  
  15.     WNDCLASS wc = {};  
  16.     wc.hInstance = hInstance;  
  17.     wc.lpszClassName = cln;  
  18.     wc.lpfnWndProc = MyWindowProc;  
  19.     //注冊窗口類  
  20.     RegisterClass(&wc);  
  21.     // 創建窗口  
  22.     HWND hMainwind = CreateWindow(  
  23.         cln,  
  24.         L"繪制窗口",  
  25.         WS_OVERLAPPEDWINDOW,  
  26.         20,  
  27.         12,  
  28.         450,  
  29.         300,  
  30.         NULL,  
  31.         NULL,  
  32.         hInstance,  
  33.         NULL);  
  34.     // 顯示窗口  
  35.     if(hMainwind == NULL)  
  36.         return 0;  
  37.     ShowWindow(hMainwind,SW_NORMAL);  
  38.     // 消息循環  
  39.     MSG msg;  
  40.     while(GetMessage(&msg,NULL,0,0))  
  41.     {  
  42.         TranslateMessage(&msg);  
  43.         DispatchMessage(&msg);  
  44.     }  
  45.     return 0;  
  46. }  
  47.   
  48. // 窗口消息處理程序  
  49. LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)  
  50. {  
  51.     switch(msg)  
  52.     {  
  53.     case WM_PAINT:  
  54.         break;  
  55.     case WM_DESTROY:  
  56.         PostQuitMessage(0);//退出程序  
  57.         return 0;  
  58.     default:  
  59.         return DefWindowProc(hwnd,msg,wParam,lParam);  
  60.     }  
  61. }  


這個程序是可以正常運行的,我們先來運行一下,看看有什么效果,當然沒什么效果,因為只是一個空白窗口。

 

窗口是正常出現了,但是,現在你試一下改變它的大小時,你人發現有問題了。

 

這時候我們看到,窗口中有一部分內容變成黑色了,也就是說它沒有被重新繪制。當我們的窗口被另一個窗口擋住,然后另一個窗口被移開,我們的程序窗口重新顯示時,會發生重繪;但我們改變窗口的大小后,窗口也會發生重繪;當我們把窗口隱藏(如最小化)后再顯示,它也會發生重繪。我們的窗口就像一堵牆,在運行期間會不斷地被重新粉刷

要讓窗口自動重繪,有一種簡單的方法,就是在注冊窗口類的時候,設置一個背景色。

[cpp]  view plain  copy
 
  1. wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);  

現在你運行的時候,改變窗口的大小,就看不到黑色區域了,因為有了背景色。而上面的代碼中,有朋友可能會問,COLOR_WINDOW + 1是什么東西,背景色為什么加1?

我們不妨看看COLOR_WINDOW 的定義。

其實這些都是數值來的,我們看到COLOR_WINDOW是5,那么 5 + 1 就是6吧,你看看6是誰?是不是COLOR_WINDOWFRAME的值?所以,你現在懂了嗎,它只是選擇COLOR_WINDOW作為參考點,因此,你可以推算到 COLOR_WINDOW - 2是哪個顏色值了。

 

當窗口需要重新粉刷時,我們的程序都會收到一條WM_PAINT消息,我們可以響應它來完成繪制。

[cpp]  view plain  copy
 
  1. // 窗口消息處理程序  
  2. LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)  
  3. {  
  4.     switch(msg)  
  5.     {  
  6.     case WM_PAINT:  
  7.         {  
  8.             PAINTSTRUCT ps;  
  9.             BeginPaint(hwnd, &ps);  
  10.             DrawText(ps.hdc, L"朋友,你好。",wcslen(L"朋友,你好。"), &(ps.rcPaint), DT_CENTER);  
  11.             EndPaint(hwnd, &ps);  
  12.         }  
  13.         return 0;  
  14. ...................  

我們也許在其他書上看到過,繪制圖形要先GetDC來獲得一個HDC,然后畫圖,畫完之后再ReleaseDC,為什么我們這里不需要這樣做?從代碼中我們看到,繪圖代碼放在BeginPaint和EndPaint之間,這是專門用在處理WM_PAINT消息用的,注意在其他地方不能這樣用。

我們用DrawText函數在窗口上繪制了一行文本,但是,在你運行程序后,如果你調整了窗口的大小,你會發現又有新問題出現了。



現在,我們還是來想一想,為啥會出現這種情況呢?

那是因為窗口不是把整個客戶區域完全重畫,而是判斷哪一部分應該重畫,就重畫,先前因為我們用的都同一種顏色的畫刷來填充背景,所以我們看不出問題所在,然現在我們在窗口上繪制了文本,問題就顯現出來了。由於每次重畫時的矩形范圍都是不同的,而且在重畫之前沒有清除前面的內容,使得新畫的東西覆蓋在原來的上面,就好像我們拿油漆在牆壁上塗鴉一樣。

窗口的客戶區域就是你看到的白色的那塊矩形,除了標題欄和邊框,剩下的那些都可以歸為客戶區域。

要解決上面問題的最簡單方法,就是在設計窗口類的時候,把類樣式同時設為水平重畫(CS_HREDRAW)和垂直重畫(CS_VREDRAW).

[cpp]  view plain  copy
 
  1. wc.style = CS_HREDRAW | CS_VREDRAW;  

現在再運行一下,哈哈,沒問題了。

上面的文本是使用默認顏色的繪制的,我想改一下文本的顏色,可以使用SetTextColor函數,第一參數接受一個hdc,第二個參數是COLORREF,通過RGB宏可以創建。如下面的例子:

[cpp]  view plain  copy
 
  1. case WM_PAINT:  
  2.     {  
  3.         PAINTSTRUCT ps;  
  4.         BeginPaint(hwnd, &ps);  
  5.         SetTextColor(ps.hdc, RGB(10, 0, 255));//設置文本顏色  
  6.         DrawText(ps.hdc, L"朋友,你好。",-1, &(ps.rcPaint), DT_CENTER);  
  7.         EndPaint(hwnd, &ps);  
  8.     }  
  9.     return 0;  


 

如果想一次性繪制多個字符串,可以調用PolyTextOut函數,但這個函數在繪制出來的字符上好像有點問題。

[cpp]  view plain  copy
 
  1. case WM_PAINT:  
  2.     {  
  3.         PAINTSTRUCT ps;  
  4.         BeginPaint(hwnd, &ps);  
  5.         SetTextColor(ps.hdc, RGB(10, 0, 255));//設置文本顏色  
  6.         DrawText(ps.hdc, L"朋友,你好。",-1, &(ps.rcPaint), DT_CENTER);  
  7.         // 用於設置每個字符間隔的數組  
  8.         int arr1[2]= {45,0};  
  9.         int arr2[3] = { 35, 40, 0 };  
  10.         int arr3[2] = { 32, 0 };  
  11.         POLYTEXT polys[] =  { {2,2,3,L"大家",ETO_CLIPPED,ps.rcPaint,&arr1[0]},  
  12.             {2,25,3,L"新年好",ETO_CLIPPED,ps.rcPaint,&arr2[0]},  
  13.             {30,60,3,L"快樂\0",ETO_CLIPPED,ps.rcPaint,&arr3[0]}  
  14.         };  
  15.         PolyTextOut(ps.hdc, &polys[0],3);  
  16.         EndPaint(hwnd, &ps);  
  17.     }  
  18.     return 0;  


 

當然也可以填充一些圖形區域。

[cpp]  view plain  copy
 
  1. // 填充圖形  
  2. // 創建畫刷  
  3. HBRUSH hb = CreateSolidBrush(RGB(0,255,0));  
  4. // 畫刷選擇到當前DC中  
  5. HBRUSH orgBrs = (HBRUSH)SelectObject(ps.hdc, hb);  
  6. // 填充圖形  
  7. Ellipse(ps.hdc,135,35,202,170);  
  8. // 選回原先的畫刷  
  9. SelectObject(ps.hdc, orgBrs);                             
  10. sp;                          DeleteObject(hb); //清理對象  


 

這樣我們就在窗口上畫了一個橢圓了。

 

響應WM_PAINT消息進行繪圖,應按照以下步驟:

1、聲明一個PAINTSTRUCT結構體的變量,用於被填充與繪圖相關的信息。

2、BeginPaint,函數調用后開始畫圖。

3、畫完之后調用EndPaint函數,HDC會被自動釋放。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM