关于"VC技术内幕"-控件上绘图代码的解释

来源:互联网 发布:php分页代码首页尾页 编辑:程序博客网 时间:2024/06/04 18:54

vc技术内幕,有一节关于在对话框上控件画图(6.8节)的代码:  

void CMyDlg::OnPaint()
{

    CWnd   *pWnd   =   GetDlgItem(IDC_STATIC1);     
    RECT   rect;  
    pWnd->GetClientRect(&rect);  
    CDC   *pControlDC   =   pWnd->GetDC();  
    pWnd->Invalidate();  
    pWnd->UpdateWindow();  
    pControlDC->SelectStockObject(BLACK_BRUSH);  
    pControlDC->Rectangle(rect.left,   rect.top,   rect.right,rect.bottom);  
    pWnd->ReleaseDC(pControlDC);
  
}

 这里连用了 pWnd->Invalidate();   pWnd->UpdateWindow();  
 原文解释:“这里面的一个技巧就在于我们既要在控件窗口内绘图,又要防止Windows对它进行重复绘制。”

 就是这两句代码(pWnd->Invalidate();   pWnd->UpdateWindow();  )让许多人摸不着头脑。
 归纳起来有两种问题:
1、认为这是死循环
  这是初学者提的问题,这里需指出:pWnd是IDC_STATIC控件的指针,并不是对当前窗体
2、对Invalidate、UpdateWindow均会引起WM_PAINT事件的不解
  “系统会在多个不同的时机发送WM_PAINT消息:当第一次创建一个窗口时,当改变窗口的大小时,当把窗口从另一个窗口背后移出时,当最大化或最小化窗口时,等等,这些动作都是由系统管理的,应用只是被动地接收该消息,在消息处理函数中进行绘制操作;大多数的时候应用也需要能够主动引发窗口中的绘制操作,比如当窗口显示的数据改变的时候,这一般是通过InvalidateRect InvalidateRgn函数来完成的。InvalidateRectInvalidateRgn把指定的区域加到窗口的Update Region中,当应用的消息队列没有其他消息时,如果窗口的Update Region不为空时,系统就会自动产生WM_PAINT消息。”最后一句话指出了问题所在,Invalidate使客户区无效,但并没有及时触发WM_PAINT,WM_PAINT是由系统控制的,只有当在消息队列没有其他消息时才触发WM_PAINT
  系统为什么不在调用Invalidate时发送WM_PAINT消息呢?又为什么非要等应用消息队列为空时才发送WM_PAINT消息呢?
  这是因为系统把在窗口中的绘制操作当作一种低优先级的操作,于是尽可能地推后做,这样有利于提高绘制的效率:在两个WM_PAINT消息之间多个Invalidate调用使之失效的区域就会被累加起来,然后在一个WM_PAINT消息中一次得到更新,不仅能避免多次重复地更新同一区域,也优化了应用的更新操作。像这种通过InvalidateRect和InvalidateRgn来使窗口区域无效,依赖于系统在合适的时机发送WM_PAINT消息的机 制实际上是一种异步工作方式,也就是说,在无效化窗口区域和发送WM_PAINT消息之间是有延迟的;有时候这种延迟并不是我们希望的,这时我们当然可以在无效化窗口区域后利用SendMessage 发送一条WM_PAINT消息来强制立即重画,但不如使用Windows GDI为我们提供的更方便和强大的函数:UpdateWindow和RedrawWindow。UpdateWindow会检查窗口的Update Region,当其不为空时才发送WM_PAINT消息;RedrawWindow则给我们更多的控制:是否重画非客户区和背景,是否总是发送WM_PAINT消息而不管Update Region是否为空等"

     

       这也就解释了代码中去掉pWnd->UpdateWindow() 后不能出现所绘图的现象,其实图像已经绘制,只不过被Invalidate滞后触发的WM_PAINT刷了 

  MSDN的解释
  pWnd->Invalidate();  
     Specifies   whether   the   background   within   the   update   region   is   to   be   erased      
  pWnd->UpdateWindow();  
     Updates   the   client   area   by   sending   aWM_PAINT   message   if   the   update   region   is   not             empty.   The   UpdateWindow   member   function   sends   a   WM_PAINT   message   directly,   bypassing   the   application   queue.   If   the   update   region   is   empty,   WM_PAINT   is   not   sent.  
  
  

原创粉丝点击