dnf飞鱼是什么:WM_PAINT详解 - ljfxmf的专栏 - CSDN博客

来源:百度文库 编辑:偶看新闻 时间:2024/05/07 12:36:02
WM_PAINT发送条件是"The WM_PAINT message is sent when the system or another application makes a request to paint a portion of an application's window."那什么时候系统或其他应用程序会发送重画请求呢?需要重画的"portion"又有多大呢?再往下看,"The message is sent when the UpdateWindow or RedrawWindow function is called, or by the DispatchMessage function when the application obtains a WM_PAINT message by using the GetMessage or PeekMessage function. "这就说明这个WM_PAINT消息既可能由系统发送,也可能由应用程序人工发送。这个很好理解。当窗口的一部分被其它窗口遮盖而复原,或者从最小化状态恢复到正常状态时,系统自然会要求窗口重画。系统重画窗口的条件可以参见MSDN\Platform SDK\Windows GDI\Painting and Drawing\When to Draw in a window. 而有时候我们需要窗口的某些部分作出改变,就得人工要求窗口重画(通过调用UpdateWindow和RedrawWindow)。比如我的基础类库里窗口上没有任何Windows意义上的控件(有hWnd),只是人为定义某一个区域是一个“按钮”,当鼠标指向这个区域时加载hover图像以获得hottrack效果。这时操作系统自然不会认为有重画的必要,但程序却必须重画,这时就得人工发送WM_PAINT消息了。注意不要傻乎乎地直接用SendMessage或PostMessage发送WM_PAINT,后面会解释原因。由于重画很费时间和资源,并且也不是应用程序的“主业”,因此系统也知道要尽量减少重画的次数。系统只在应用程序的消息队列为空的时候才发送WM_PAINT,这就是为什么当程序死锁时窗口图像不会更新。同样为了减少重画的工作量,Windows提出了update region的概念,"The update region identifies the portion of a window that is out-of-date or invalid and in need of redrawing. The system uses the update region to generate WM_PAINT messages for applications and to minimize the time applications spend bringing the contents of their windows up to date. "也就是说,Windows会判断窗口的哪些区域需要重画,这个区域就是update region. 比如原来在窗口上面的一个窗口现在挪走了,系统就把新露出来的区域定义为update region(这个过程称为invalidate)。系统不断检测一个窗口的update region是否为空,当update region不为空并且应用程序没有消息要处理(消息队列为空)的时候,系统就通过WM_PAINT告诉应用程序“现在没事干了?窗口的一部分需要重画,你把这一部分重画一下”。应用程序重画了窗口之后,把update region重新设置为空(这个过程称为validate),如此不断循环。如果消息队列不为空,系统就把update region不断更新(采用取并集的方法),等消息队列为空的时候一起处理。这就大大减少了重画的次数。这样你或许就明白了为什么不能直接用SendMessage和PostMessage发送WM_PAINT的原因:由于没有invalidate,系统认为窗口没有更新的必要,于是就对发来的WM_PAINT消息不理不睬。解决方案就是——我们自己invalidate!相关的API就是InvalidateRect()和InvalidateRgn(). 画完了之后用ValidateRect()和ValidateRgn()告诉系统“我画完了”就行了。可以把invalidate过程看成类似CombineRgn()取并集,把validate过程看成取差集即可。还有一些相关的API: GetUpdateRect(), GetUpdateRgn(), ExcludeUpdateRgn(), 从名字就能猜出个大概,各位可以自行去查MSDN.在WM_PAINT消息处理过程中有两个不得不提到的函数:BeginPaint()和EndPaint(). 只有WM_PAINT消息处理能使用这两个函数。实际上默认消息处理函数DefWindowProc()对WM_PAINT的处理方式就是:case WM_PAINT:    PAINTSTRUCT ps;    BeginPaint (hWnd, &ps);    EndPaint (hWnd, &ps);    return 0;BeginPaint()和EndPaint()之所以不可或缺,就是因为它们实现了validate过程。BeginPaint()的主要任务之一就是validate. 如果在WM_PAINT的消息处理中直接return 0,update region就始终不为空,系统就会不停地发送WM_PAINT消息。EndPaint()负责释放BeginPaint()返回的DC,做好善后工作(比如重新显示BeginPaint()隐藏起来的光标)。最后还有一点需要额外说明:用WM_PAINT处理重画是异步(asynchronous)的。也就是说,在invalidate之后窗口并不会立即重画而是等到消息队列为空时再重画,这样就有一个时间差。这个事件差有时短到不被注意,但有时就是个大问题(尤其是当程序需要执行耗费时间的任务,如串口I/O)。这时可以采用同步重画法,直接用GetDC()获得hDC执行重画操作。如果非要使用WM_PAINT来同步重画(个人比较喜欢这种方法,和重画有关的代码就应该在WM_PAINT的处理程序里嘛),可以使用UpdateWindow()和RedrawWindow(). 这两个API函数会直接把WM_PAINT送进窗口的消息队列而不是应用程序的消息队列,这样就不用等到最后了。注意前者当update region不为空时才会发送WM_PAINT,后者的控制选项更为丰富。 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/ljfxmf/archive/2008/06/05/2513221.aspx