现在的位置: 首页 > 综合 > 正文

这里Invalidate()能够代替RedrawWindow()的工作

2013年12月02日 ⁄ 综合 ⁄ 共 2166字 ⁄ 字号 评论关闭

继续WTL的学习,在第二部分的WTL Clock程序中,当定时器抛出WM_TIMER消息时,处理器OnTimer做了这样的工作:

而用来更新时间的处理器OnPaint由WM_PAINT消息激发,显然WM_PAINT是由RedrawWindow()抛出的。  

如果直接用PostMessage(WM_PAINT)来代替RedrwaWindow(),编译运行,发现窗口显示的时间没能如愿的每隔1Sec更新。为什么?明明手动抛出了WM_PAINT消息,按理说,它应该激发OnPaint函数来处理这个消息嘛。 

F12查看RedrawWindow()代码,如下:

很明显它是对Platform SDK函数RedrawWindow的简单封装,通过查看MSDN,容易了解到RedrawWindow函数干了两件事:

  1. 对窗口进行“Invalidate”,也就是声明待更新区域“过期”
  2. 抛出WM_NCPAINT,WM_ERASEBKGND,WM_PAINT等消息

好了,了解RedrawWindow足够多了。我们发现,在WTL Clock程序中,我们只需要WM_PAINT消息,但试验证明PostMessage(WM_PAINT)起不了作用,它取代不了RedrawWindow函数。我们唯一漏掉的就是窗口的“Invalidate”(过期声明)。在MSDN中搜索Invalidate,刚好得到一个CWindowImpl::Invalidate()成员函数,而WTLClockView类刚好继承于CWindowImpl,所以在它内部可以直接调用Invalidate()的。

进一步查看Invalidate()的说明,有这样一句话:“Invalidates the entire client area. Passes NULL for the RECT parameter to the InvalidateRect Win32 function”,意思就是说函数将会声明整个客户区过期,而本例中view正是客户区。另外,它是对Win32函数的封装,查看InvalidateRect的说明,再链接到Invalidating
the Client Area的说明,第一句话是:
“The system is not the only source ofWM_PAINT messages. TheInvalidateRect
or
InvalidateRgn function can indirectly generate WM_PAINT messages for your windows.” 它告诉我们系统不是WM_PAINT消息的唯一来源,函数InvalidateRect或InvalidateRgn同样可以直接为你的窗口生成WM_PAINT消息。看来,Invalidate()已经完全满足本程序的要求了:声明客户区(本例中的view区域)“过期”,并抛出了我们需要的WM_PAINT消息,这将驱动OnPaint()对时间进行更新。所以OnTimer()函数可以修改为:

连PostMessage(WM_PAINT)都不用写。编译运行,结果正如所需要的那样。 

 

P.S:

Windows规范是禁止用户主动抛WM_PAINT消息的,WM_PAINT消息应该由InvalidateRect等函数来激发。只要客户区存在无效区域,消息队列中就包含一条WM_PAINT消息,但该消息的优先级很低,只有在没有其它消息的情况下才被GetMessage函数抓取到。多条WM_PAINT消息通过综合无效区域合并为一条。API函数RedrawWindow比Invalidate功能强大得多,二者有很大的不同,但在本例中它们都用于无效化整个客户区使之重绘。区别在于本例中的RedrawWindow是立马进行绘制,而Invalidate引起的WM_PAINT何时被处理是不确定的。(2013-06-22)

抱歉!评论已关闭.