1、什么是有效矩形,什么是无效矩形
当程序中遇到图像或文字显示时系统会发送一个WM_PAINT消息,当应用程序收到消息后通常就准备更新整个显示区域,但是通常只需要更新一个比较小的区域而不是整个区域,这种情况通常出现在当应用程序的主窗口的一部分被一个对话框覆盖,需要重画的只是被覆盖的矩形区域.这个矩形区域就是有效矩形.
windows内部为每个窗口都保留了一个绘图结构(PAINTSTRUCT),他包含了包围无效区域的最小矩形的坐标和一些其他信息,需要注意的是,当窗口消息处理函数在处理WM_PAINT消息之前显示区域中出现了另一个无效区域即无效矩形,那么windows会计算出一个包围两个无效区域的新无效区域,并把这种变化保存在绘图结构(PAINTSTRUCT)中,windows是不会同时把多个WM_PAINT消息同时放在消息队列中的.
窗口消息处理函数是通过调用InvalidateRect函数使窗口显示区域内的矩形变为无效的,如果消息队列中已经存在一个WM_PAINT,那么windows会计算出新的无效矩形,在接收到WM_PAINT消息的时候,窗口消息处理函数可以获得无效矩形的坐标,通过调用GetUpdateRect,可以在任何时候获得这些坐标.
下面这段话更容易理解:
有效矩形和无效矩形
尽管窗口消息处理程序一旦接收到WM_PAINT消息之后,就准备更新整个显示区域,但它经常只需要更新一个较小的区域(最常见的是显示区域中的矩形区域)。显然,当对话框覆盖了部分显示区域时,情况即是如此。在擦除对话框之后,需要重画的只是先前被对话框遮住的矩形区域。
这个区域称为「无效区域」或「更新区域」。正是显示区域内无效区域的存在,才会让Windows将一个WM_PAINT消息放在应用程序的消息队列中。只有在显示区域的某一部分失效时,窗口才会接受WM_PAINT消息。
Windows内部为每个窗口保存一个「绘图信息结构」,这个结构包含了包围无效区域的最小矩形的坐标以及其它信息,这个矩形就叫做「无效矩形」,有时也称为「无效区域」。如果在窗口消息处理程序处理WM_PAINT消息之前显示区域中的另一个区域变为无效,则Windows计算出一个包围两个区域的新的无效区域(以及一个新的无效矩形),并将这种变化后的信息放在绘制信息结构中。Windows不会将多个WM_PAINT消息都放在消息队列中。
窗口消息处理程序可以通过呼叫InvalidateRect使显示区域内的矩形无效。如果消息队列中已经包含一个WM_PAINT消息,Windows将计算出新的无效矩形。否则,它将一个新的WM_PAINT消息放入消息队列中。在接收到WM_PAINT消息时,窗口消息处理程序可以取得无效矩形的坐标(我们马上就会看到这一点)。通过呼叫GetUpdateRect,可以在任何时候取得这些坐标。
在处理WM_PAINT消息处理期间,窗口消息处理程序在呼叫了BeginPaint之后,整个显示区域即变为有效。程序也可以通过呼叫ValidateRect函数使显示区域内的任意矩形区域变为有效。如果这呼叫具有令整个无效区域变为有效的效果,则目前队列中的任何WM_PAINT消息都将被删除。
编程编程,不编咋成?
2、获取或释放设备描述表句柄以及相关操作
当应用程序需要绘图的时候,必须先获取设备描述表句柄,绘图操作结束后必须释放设备描述表句柄。获取和释放设备描述表句柄有两种方法。
1)使用BegingPaint和EndPaint函数
通常是在应用程序接收到 WM_PAINT消息,也就是需要更新窗口的显示区域的时候调用BeginPaint函数来获取设备描述表句柄的,使用完后调用EndPaint函数释放设备描述表句柄.
BeginPaint
The BeginPaint function prepares the specified window for painting and fills a PAINTSTRUCT structure with information about the painting.
HDC BeginPaint( HWND hwnd, // handle to window LPPAINTSTRUCT lpPaint // paint information );
Parameters
-
hwnd
- [in] Handle to the window to be repainted. lpPaint
- [out] Pointer to the PAINTSTRUCT structure that will receive painting information.
Return Values
If the function succeeds, the return value is the handle to a display device context for the specified window.
If the function fails, the return value is NULL, indicating that no display device context is available.
Windows NT/2000/XP: To get extended error information, call GetLastError .
Remarks
The BeginPaint function automatically sets the clipping region of the device context to exclude any area outside the update region. The update region is set by the InvalidateRect or InvalidateRgn function and by the system after sizing, moving, creating, scrolling, or any other operation that affects the client area. If the update region is marked for erasing, BeginPaint sends a WM_ERASEBKGND message to the window.
An application should not call BeginPaint except in response to a WM_PAINT message. Each call to BeginPaint must have a corresponding call to the EndPaint function.
If the caret is in the area to be painted, BeginPaint automatically hides the caret to prevent it from being erased.
If the window's class has a background brush, BeginPaint uses that brush to erase the background of the update region before returning.
Example Code
For an example, see Drawing in the Client Area.
Requirements
Windows NT/2000/XP/Vista: Included in Windows NT 3.1 and later.
Windows 95/98/Me: Included in Windows 95 and later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.
事实上程序员只需关心前三个属性.
第一个属性hdc,表示当前的设备描述表句柄.
第二个属性fErase,多数情况下是被标记成FALSE(0)的,这表示windows已经擦除了无效矩形的背景,这个擦除动作是在BeginPaint函数中发生的,擦除背景用的画刷则是WNDCLASS结构中的hbrBackground属性指定的画刷,在很多情况下,程序作者可能想自己定义一些擦除行为,那么可以通过响应消息队列中的WM_ERASEBAGND消息来完成.
第三个属性rcPaint,表示无效矩形坐标,它定义了无效矩形的边界.
注意,在前面提到了InvalidateRect函数,并已经清楚了调用他可以让窗口显示区域内的矩形变为无效,那么可以在处理WM_PAINT消息的时候通过调用他实现在无效矩形外绘图.该调用是在调用BegingPaint函数之前进行的.
使用方法:
InvalidateRect(hwnd,NULL,TRUE);
通过上面的代码的调用整个显示区域变为了无效,并擦除了背景.要注意的是,最后一个参数如果为FALSE,则不擦除背景,原有的东西将保留在原处,这通常是在接收到wm_paint消息而且不在考虑rcPaint属性的情况下简单地重绘整个显示区域最方便的方法,例如,在显示区域内输出了一个图形,这个图形的一小部分落在了无效矩形区域内,而这就让绘制此图形的无效部分变得没有意义,需要绘整个图形,因为在调用BeginPaint函数传回设备描述表句柄的时候,windows不会绘制rcPaint也就是无效矩形以外的任何部分.
2、使用GetDc和ReleaseDc函数
两种方法的区别:
(1)使用BeginPaint函数获得的操作区域是显示区域中的无效矩形区域,接下来的绘图操作只能在窗口的无效区域范围内进行,无效区域以外的区域被忽略不能进行操作,而GetDC函数获得的操作区域是整个窗口的显示区域,之后的操作可以在任何部分进行,而不限制在无效区域.
(2) BeginPaint函数会自动把无效区域变为有效区域,而GetDC函数不会将任何无效区域变得有效,必须通过强行调用ValidateRect函数,并把第二个参数设置为NULL来完成.
字体操作的函数:
TextOut函数:
什么是系统字体:系统字体是windows用来在标题栏,功能表和对话框中显示字符串所使用的默认字体.