知了博客

集天地之精华,吸日月之灵气

« 递归实现阶乘递归算法学习系列之经典背包问题 »

窗口刷新问题(WM_PAINT、BeginPaint、EndPaint的说明)

来源:看文章
Windows API编程,WM_PAINTWindows窗口个重消息,应程序就通过响应这个消息完成窗口绘制。

  The WM_PAINT message is generated by the system and should not be sent by an application.The system sends this message when there are no other messages in the application's message queue

  注意:WM_PAINT消息由系统产生,非等应程序消息队列空时才发送WM_PAINT消息 。

  其实系统不同机制发送WM_PAINT消息,比如调UpdateWindow函数,第次创建窗口,改变窗口,最化,最化等等。这些动作产生都有系统控制,应程序只接收消息,并处理消息。

  当Window检测窗口被覆盖地方需恢复时候,向户程序发送个WM_PAINT消息,消息包括需恢复区域,然由户程序决定恢复被覆盖容。窗口过程收WM_PAINT消息,并不代表整个客户区都需被刷新,有能客户区被覆盖区域只有块,这个区域叫做“无效区域”,程序只需更新这个区域。WM_TIMER消息类似,WM_PAINT消息个级别消息,虽然不像WM_TIMER消息样被丢弃,但Windows总消息循环空时候才WM_PAINT放入其,实际,Windows每个窗口维护个“绘图信息结构”,无效区域坐标就其,每当消息循环空时候,如果Windows存个无效区域,就放入个WM_PAINT消息。

  无效区域坐标并不附带WM_PAINT消息参数,程序有其以获,WM_PAINT消息只通知程序有个区域需更新而已,所以Windows不同时两条WM_PAINT消息放入消息循环,当Windows放入条WM_PAINT消息时候,如果已经存个无效区域,那么只需新旧两个无效区域合并计算出个无效区域就以,消息循环还只需条WM_PAINT消息。
如果程序WM_PAINT消息客户区刷新完毕工作并没有结束,如果不使无效区域变得有效,Windows轮消息循环继续放入个WM_PAINT消息,而不根据程序否执行刷新过程,所以程序以不去刷新客户区,而简单地个ValidateRect函数直接让客户区变得有效,以此“欺骗”Windows已经没有无效区域,当Windows检查“绘图信息结构”时候没有无效区域,就不继续发送WM_PAINT消息。

  那么“绘图信息结构”怎么获呢?BeginPaint函数第二个参数个绘图信息结构缓冲区地址,windows这里返回绘图信息结构,结构包含无效区域位置,绘图信息结构定义如:

typedef struct tagPAINTSTRUCT { // ps 
    HDC   hdc; 
    BOOL fErase; 
     RECT rcPaint; 
    BOOL fRestore; 
    BOOL fIncUpdate; 
    BYTE rgbReserved[32]; 
} PAINTSTRUCT; 

  其hdc字段窗口设备环境句柄,rcPaint字段个RECT结构,指定无效区域矩形角顶点,fErase字段如果非零值,表示Windows发送WM_PAINT消息已经使背景色擦除无效区域,面3个字段Windows部使,应程序不必去理们。

  摘自《Windows环境32位汇编语言程序设计》

  数Windows程序WinMain进入消息循环始化期间都呼叫函数UpdateWindow。Windows利这个机给窗口消息处理程序发送第个WM_PAINT消息。这个消息通知窗口消息处理程序:必须绘制显示区域。此,窗口消息处理程序应任何时刻都准备好处理其WM_PAINT消息,必话,甚至重新绘制窗口整个显示区域。发生面几种事时,窗口消息处理程序接收个WM_PAINT消息:
使移动窗口或显示窗口时,窗口先被隐藏区域重新见。

   使改变窗口(如果窗口类别样式有着CS_HREDRAWCS_VREDRAW位旗标设定)。

   程序使ScrollWindow或ScrollDC函数滚动显示区域部分。

  程序使InvalidateRect或InvalidateRgn函数刻意产生WM_PAINT消息。

  某些,显示区域部分被临时覆盖,Windows试图保存个显示区域,并以恢复,但这不定能成功。以,Windows能发送WM_PAINT消息:

   Windows擦除覆盖部分窗口话框或消息框。

   拉出,然被释放。

  显示工具提示消息。

  某些,Windows总保存所覆盖显示区域,然恢复。这些:

  鼠标光标穿越显示区域。

  图标拖过显示区域。

  处理WM_PAINT消息求程序作改变自己向显示器输出思维方式。程序应该组织成以保留绘制显示区域需所有信息,并且仅当「响应求」-即Windows给窗口消息处理程序发送WM_PAINT消息时才进行绘制。如果程序其时间需更新其显示区域,以强制Windows产生个WM_PAINT消息。这看似屏幕显示容种舍近求远。但您程序结构以从受益。

  1. 系统何时发送WM_PAINT消息?

  系统个不同时机发送WM_PAINT消息:当第次创建个窗口时,当改变窗口时,当窗口从另个窗口背移出时,当最化或最化窗口时,等等,这些动作都由 系统管理,应只被动地接收该消息,消息处理函数进行绘制操作;数时候应需能够主动引发窗口绘制操作,比如当窗口显示数据改变时候,这般通过InvalidateRect InvalidateRgn函数完成。InvalidateRectInvalidateRgn指定区域加窗口Update Region,当应消息队列没有其消息时,如果窗口Update Region不空时,系统就自动产生WM_PAINT消息。
系统什么不调Invalidate时发送WM_PAINT消息呢?又什么非等应消息队列空时才发送WM_PAINT消息呢?这因系统窗口绘制操作当作种优先级操作,于尽 能地推做。不过这样有利于提绘制效率:两个WM_PAINT消息间通过InvalidateRectInvaliateRgn使失效区域就被累加起,然个WM_PAINT消息次得 更新,不仅能避免次重复地更新同区域,优化应更新操作。像这种通过InvalidateRectInvalidateRgn使窗口区域无效,依赖于系统合适时机发送WM_PAINT消息机 制实际种异步工作方式,就说,无效化窗口区域发送WM_PAINT消息间有延迟;有时候这种延迟并不们希望,这时们当然以无效化窗口区域利SendMessage 发送条WM_PAINT消息强制立即重画,但不如使Windows GDI们提供更方便强函数:UpdateWindowRedrawWindow。UpdateWindow检查窗口Update Region,当其不空时才发送WM_PAINT消息;RedrawWindow则给们更控制:否重画非客户区背景,否总发送WM_PAINT消息而不管Update Region否空等。

  2. BeginPaint

  今天处理WM_PAINT消息时产生个级误,并搞花快个时才找原因。处理消息时,没有使BeginPaintEndPaint这函数,结果其余消息弹不出,窗口拖动时,不停闪烁(其实那就重绘)。还MSDN找答案,现原话贴出。(MSDNThe WM_PAINT Message标题)

  BeginPaint sets the update region of a window to NULL. This clears the region, preventing it fromgenerating subsequent WM_PAINT messages. If an application processes a WM_PAINT message but does not call BeginPaint or otherwise clear the update region, the application continues to receive WM_PAINT messages as long as the region is not empty. In all cases, an application must clear the update region before returning from the WM_PAINT message. 
 BeginPaint函数作就窗口需重绘区域设置空(就Update Region置空)。常,们接收WM_PAINT消息,窗口Update Region都非空(如果空就不需发送WM_PAINT消息)。而当响应这个消息时候又不调BeginPaint清空,窗口Update Region就直非空,系统就直发送WM_PAINT消息。这样就形成个处理WM_PAINT消息死循环。这就出现误原因,级误。

  BeginPaintWM_PAINT消息紧密相关。试试WM_PAINT处理函数不BeginPaint怎样?程序像进入个死循环样达惊人CPU占率,程序总处理个接 个WM_PAINT消息。这因通常,当应收WM_PAINT消息时,窗口Update Region都非空(如果空就不需发送WM_PAINT消息),BeginPaint个作就该Update Region置空,这样如果不调BeginPaint,窗口Update Region就直不空,如所述,系统就直发送WM_PAINT消息。

  BeginPaintWM_ERASEBKGND消息有关系。当窗口Update Region被标志需擦除背景时,BeginPaint发送WM_ERASEBKGND消息重画背景,同时其返回信息里有个标志表明窗口背景否被重画过。当们InvalidateRectInvalidateRgn指定区域加Update Region时,以设置该区域否需被擦除背景,这样个BeginPaint就知道否需发送WM_ERASEBKGND消息。

  当然关于 WM_PAINT消息还有知识需学习。另注意点,BeginPaint只能WM_PAINT处理函数使,并且调BeginPaint函数,不忘记调EndPaint函数,们。

  3.重画函数 InvalidateRect,UpdateWindow, RedrawWindow区别

  InvalidateRect通过线程消息队列发送刷新消息,最常。 

  UpdateWindow直接调窗口函数立即响应刷新消息,使窗口刷新消息优先被响应(消息队列如果没有WM_PAINT消息就什么都不执行),般ShowWindow调。 

  RedrawWindow相当于先调InvalidateRect,紧接着又调UpdateWindow,此RedrawWindow还提供些两没法做功能。

  补充几点:

  1.WM_Paint 个被动消息,不能通过普通简单 sendmessage WM_paint 事这不行;但通过消息由程序员引发不不能;通过几个特殊常数以做,不过delphi找

  2.sendmessage 以消息发送消息队列;但windows自动判断否存无效画图区域;如果存无效画图区域,则能重画,反则弃该消息.

  3.以使 InvalidateRect 等几个APi屏幕任意个个矩形区域设置无效区域,UpdateWindow调,windows自动查找否存无效,并重画,该矩形区域;

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

日历

最新评论及回复

最近发表

Powered By Z-Blog 1.8 Arwen Build 90619 Code detection by Codefense  theme by BokeZhuti

Copyright know blog. Some Rights Reserved.站长(msn):webmaster#webgou.info(#换成@) 粤ICP备09183716号