关于WM_PAINT消息中只重绘无效区的问题

一直以来我都有一个疑问,那就是下面的代码

	case WM_PAINT :
		hdc = BeginPaint (hwnd, &ps);
                ...............
		EndPaint (hwnd, &ps) ;
		return 0 ;

其中的BeginPaint(hwnd,&ps)通过ps结构体中的一个矩形结构体变量标识的无效区来重绘窗口,而且重点是只重绘无效区。

那么如果我代码中的省略处的代码在整个窗口上绘制,难道窗口无效时发送WM_PAINT消息就只重绘无效区吗?

Windows系统真可谓博大精深,想要了解个透彻真可谓不易啊!不过我一直都在努力着去了解的更深刻,菜鸟不停的飞,总有一天会飞成老鸟的,因为岁月不饶人吗!嘿嘿。

学习Windows程序设计的过程中总会有这样那样的疑问,我那愚钝的脑袋一时半会真的很难解决,不过人家系统那样搞自然会有它的依据,只是现在自己知识浅薄,看不透人家那样做的原因。所以把遇到的问题记录下来,好让顿悟的那天有个翻查记录的机会。

也许你也有同样的困惑,但是人家系统确实是那样做的。不信,咱们拿一个程序试试,便一切都了然了

#include <windows.h>

#define ID_TIMER    1

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
	static TCHAR szAppName[] = TEXT ("Beeper1") ;
	HWND         hwnd ;
	MSG          msg ;
	WNDCLASS     wndclass ;
	
	wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
	wndclass.lpfnWndProc   = WndProc ;
	wndclass.cbClsExtra    = 0 ;
	wndclass.cbWndExtra    = 0 ;
	wndclass.hInstance     = hInstance ;
	wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
	wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
	wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
	wndclass.lpszMenuName  = NULL ;
	wndclass.lpszClassName = szAppName ;
	
	if (!RegisterClass (&wndclass))
	{
		MessageBox (NULL, TEXT ("Program requires Windows NT!"), 
			szAppName, MB_ICONERROR) ;
		return 0 ;
	}
	
	hwnd = CreateWindow (szAppName, TEXT ("Beeper1 Timer Demo"),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT,
		CW_USEDEFAULT, CW_USEDEFAULT,
		NULL, NULL, hInstance, NULL) ;
	
	ShowWindow (hwnd, iCmdShow) ;
	UpdateWindow (hwnd) ;
	
	while (GetMessage (&msg, NULL, 0, 0))
	{
		TranslateMessage (&msg) ;
		DispatchMessage (&msg) ;
	}
	return msg.wParam ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static BOOL fFlipFlop = FALSE ;
	HBRUSH      hBrush ;
	HDC         hdc ;
	PAINTSTRUCT ps ;
	RECT        rc, rect;

	rect.left	= 100;   //在这里设定一个矩形区域,当做无效区
	rect.top	= 100;
	rect.right	= 500;
	rect.bottom	= 500;
	
	switch (message)
	{
	case WM_CREATE:
		SetTimer (hwnd, ID_TIMER, 1000, NULL) ;
		//这里设置一个定时器,每隔1s发送一个WM_TIMER消息
		return 0 ;
		
	case WM_TIMER :
		MessageBeep (-1);          
		fFlipFlop = !fFlipFlop ;

		InvalidateRect (hwnd, &rect, FALSE);
                //这里我们在每一次接受一个WM_TIMER消息时,就通过这个调用使rect标识的矩形区域标识为无效
                //窗口出现无效区时会向消息队列中发送WM_PAINT
                //按照hdc = BeginPaint (hwnd, &ps);会使无效区域有效,也即是通过只重绘无效区域使窗口变的有效
		//我们在WM_PAINT消息中调用FillRect (hdc, &rc, hBrush);让rc标识整个窗口客户区,也就是绘制整个窗口客户区
                //我们通过fFlipFlop来决定绘制蓝色还是红色
                //运行程序你发现窗口中只在左上角的标识的无效矩形区域出现红色,其它区域永远都是蓝色
                //由此可以说明WM_PAINT消息中确实只重绘无效区
                return 0 ;
		
	case WM_PAINT :
		hdc = BeginPaint (hwnd, &ps) ;
		
		GetClientRect (hwnd, &rc) ;
		hBrush = CreateSolidBrush (fFlipFlop ? RGB(255,0,0) : RGB(0,0,255)) ;
		//Sleep(1000);
		FillRect (hdc, &rc, hBrush) ;
		EndPaint (hwnd, &ps) ;
		DeleteObject (hBrush) ;
		return 0 ;

/*通过这段代码可以测试WM_TIMER消息的优先级比较低
	case WM_LBUTTONDOWN:
		Sleep(5000);	//WM_TIMER消息的优先级比较低
		return 0 ;
*/

	case WM_DESTROY :
		KillTimer (hwnd, ID_TIMER) ;//清除定时器一定不能忘
		PostQuitMessage (0) ;
		return 0 ;
	}
	return DefWindowProc (hwnd, message, wParam, lParam) ;
}


你也可以把代码拷贝到你的编译器里面试一试,看看究竟是怎样的!


你可能感兴趣的:(编程,Win32,C语言)