zoukankan      html  css  js  c++  java
  • MFC中的Invalidate、OnDraw、OnPaint函数的作用

     MFC中的Invalidate、OnDraw、OnPaint函数的作用

     

    CWnd::Invalidate

    voidInvalidate( BOOL bErase = TRUE );

      该函数的作用是使 整个窗口客户区无效。窗口的客户区无效意味着需要重绘,例如,如果一个被其它窗口遮住的窗口变成了前台窗口,那么原来被遮住的部分就是无效的,需要重绘。 这时Windows会在应用程序的消息队列中放置WM_PAINT消息。MFC为窗口类提供了WM_PAINT的消息处理函数 OnPaint,OnPaint负责重绘窗口。视图类有一些例外,在视图类的OnPaint函数中调用了OnDraw函数,实际的重绘工作由OnDraw 来完成。参数bErase为TRUE时,重绘区域内的背景将被擦除,否则,背景将保持不变。 
      它和 UpdateWindow( )区别在于: 
      UpdateWindow()的作用是使窗口立即重绘。调用Invalidate等函数后窗口不会立即重绘,这是由于WM_PAINT消息的优先级很 低,它需要等消息队列中的其它消息发送完后才能被处理。调用UpdateWindow函数可使WM_PAINT被直接发送到目标窗口,从而导致窗口立即重 绘。

     

    CWnd::OnPaint
    afx_msg void OnPaint(); 
      说明: 
      当Windows或应用程序请求重画应用程序窗口的一部分时,框架调用这个成员函数。WM_PAINT在调用UpdateWindow或 RedrawWindow成员函数时发出。当设置了RDW_INTERNALPAINT标志并调用RedrawWindow成员函数时,窗口可能会接收到 内部重画消息。在这种情况下,窗口可能没有更新区域。应用程序必须调用GetUpdateRect成员函数以确定窗口是否具有更新区域。如果 GetUpdateRect返回0,则应用程序不应调用BeginPaint和EndPaint成员函数。 
      应用程序负责检查是否需要内部重画或更新,这可通过查看每条WM_PAINT消息的内部数据结构来完成,因为一条WM_PAINT可能是由于一个无效区域或由于使用RDW_INTERNALPAINT标志调用了RedrawWindow成员函数而引起的。 
      Windows只发送一次内部WM_PAINT消息。在通过UpdateWindow成员函数向窗口发送了内部WM_PAINT消息以后,将不会再向 窗口发送其它WM_PAINT消息,直到再次使用RDW_INTERNALPAINT标志调用了RedrawWindow成员函数。

     

    OnDraw与OnPaint有什么区别?
    OnPaint是WM_PAINT消息的消息处理函数,在OnPaint中调用OnDraw,一般来说,用户自己的绘图代码应放在OnDraw中。

    OnPaint()是 CWnd的类成员,负责响应WM_PAINT消息。OnDraw()是CVIEW的成员函数,没有响应消息的功能.当视图变得无效时(包括大小的改变,移 动,被遮盖等等),Windows发送WM_PAINT消息。该视图的OnPaint处理函数通过创建CPaintDC类的DC对象来响应该消息并调用视 图的OnDraw成员函数.OnPaint最后也要调用OnDraw,因此一般在OnDraw函数中进行绘制。
    The WM_PAINT message is sent when the UpdateWindow or RedrawWindowmember function is called.
    在OnPaint中,将调用BeginPaint,用来获得客户区的显示设备环境,并以此调用GDI函数执行绘图操作。在绘图操作完成后,将调用EndPaint以释放显示设备环境。而OnDraw在BeginPaint与EndPaint间被调用。

    1)在mfc结构里OnPaint是CWnd的成员函数. OnDraw是CView的成员函数.
    2)OnPaint()调用OnDraw(),OnPrint也会调用OnDraw(),所以OnDraw()是显示和打印的共同操作。

    OnPaint是 WM_PAINT消息引发的重绘消息处理函数,在OnPaint中会调用OnDraw来进行绘图。OnPaint中首先构造一个CPaintDC类得实 例,然后一这个实例为参数来调用虚函数OnPrepareDC来进行一些绘制前的一些处理,比设置映射模式,最后调用OnDraw。而OnDraw和 OnPrepareDC不是消息处理函数。所以在不是因为重绘消息所引发的OnPaint导致OnDraw被调用时,比如在OnLButtonDown等 消息处理函数中绘图时,要先自己调用OnPrepareDC。 
    至于CPaintDC和CClientDC根本是两回事情CPaintDC是一个设备环境类,在OnPaint中作为参数传递给OnPrepareDC来 作设备环境的设置。真正和CClientDC具有可比性的是CWindowDC,他们一个是描述客户区域,一个是描述整个屏幕。
    如果是对CVIEW或从CVIEW类派生的窗口绘图时应该用OnDraw。


    OnDraw()和OnPaint()的区别:
    首先:我们先要明确CView类派生自CWnd类。而OnPaint()是CWnd的类成员,同时负责响应WM_PAINT消息。OnDraw()是 CVIEW的成员函数,并且没有响应消息的功能。这就是为什么你用VC成的程序代码时,在视图类只有OnDraw没有OnPaint的原因。而在基于对话 框的程序中,只有OnPaint。
    其次:我们在第《每天跟我学MFC》3的开始部分已经说到了。要想在屏幕上绘图或显示图形,首先需要建立设备环境DC。其实DC是一个数据结构,它包含输 出设备(不单指你17寸的纯屏显示器,还包括打印机之类的输出设备)的绘图属性的描述。MFC提供了CPaintDC类和CWindwoDC类来实时的响 应,而CPaintDC支持重画。当视图变得无效时(包括大小的改变,移动,被遮盖等等),Windows将 WM_PAINT 消息发送给它。该视图的OnPaint 处理函数通过创建 CPaintDC 类的DC对象来响应该消息并调用视图的OnDraw 成员函数。通常我们不必编写重写的 OnPaint 处理成员函数。

    OnDraw中可以绘制用户区域。OnPaint中只是当窗口无效时重绘不会保留CClientDC绘制的内容。

    这两个函数有区别也有联系:

    1、区别:OnDraw是一个纯虚函数,定义为virtual void OnDraw(CDC* pDC ) =0; 而OnPaint是一个消息响应函数,它响应了WM_PANIT消息,也是是窗口重绘消息。

    2、联系:我们一般在 视类中作图的时候,往往不直接响应WM_PANIT消息,而是重载OnDraw纯虚函数,这是因为在CVIEW类中的WM_PANIT消息响应函数中调用 了OnDraw函数,如果在CMYVIEW类中响应了WM_PAINT消息,不显式地调用OnDraw函数的话,是不会在窗口重绘的时候调用OnDraw 函数的。

    应用程序中几乎所有的绘图都在视图的 OnDraw成员函数中发生,必须在视图类中重写该成员函数。(鼠标绘图是个特例,这在通过视图解释用户输入中讨论。)


    OnDraw重写:
    通过调用您提供的文档成员函数获取数据。
    通过调用框架传递给 OnDraw 的设备上下文对象的成员函数来显示数据。
    当文档的数据以某种方式更改后,必须重绘视图以反映该更改。默认的 OnUpdate实现使视图的整个工作区无效。当视图变得无效时,Windows 将 WM_PAINT 消息发送给它。该视图的 OnPaint处理函数通过创建 CPaintDC 类的设备上下文对象来响应该消息并调用视图的 OnDraw 成员函数。

    当没有添加WM_PAINT消息处理时,窗口重绘时,由OnDraw来进行消息响应...当添加WM_PAINT消息处理时,窗口重绘时,WM_PAINT消息被投递,由OnPaint来进行消息响应.这时就不能隐式调用OnDraw了.必须显式调用(  CDC *pDC=GetDC(); OnDraw(pDC);  )..
    隐式调用:当由OnPaint来进行消息响应时,系统自动调用CView::OnDraw(&pDC).


    想象一下,窗口显示的内容和打印的内容是差不多的,所以,一般情况下,统一由OnDraw来画。窗口前景需要刷新时,系统会会调用到OnPaint,而OnPaint一般情况下是对DC作一些初始化操作后,调用OnDraw()。


    OnEraseBkGnd(),是窗口背景需要刷新时由系统调用的。明显的一个例子是设置窗口的背景颜色(你可以把这放在OnPaint中去做,但是会使产生闪烁的现象)。  
    至于怎么界定背景和前景,那要具体问题具体分析了,一般情况下,你还是很容易区别的吧。


    的确,OnPaint()用来响应WM_PAINT消息,视类的OnPaint()内部根据是打印还是屏幕绘制分别以不同的参数调用OnDraw()虚函数。所以在OnDraw()里你可以区别对待打印和屏幕绘制。
    其实,MFC在进行打印前后还做了很多工作,调用了很多虚函数,比如OnPreparePrint()等。


    对于OnDraw() 
    This method is called by the framework to render an image of thedocument. The framework calls this method to perform screendisplay, printing, and print preview, and it passes a differentdevice context in each case. There is no defaultimplementation.


    ///CView默认的标准的重画函数
    void CView::OnPaint() //见VIEWCORE.CPP
    {

    CPaintDCdc(this);
    OnPrepareDC(&dc);
    OnDraw(&dc);   //调用了OnDraw
    }
    ///CView默认的标准的OnPrint函数
    void CView::OnPrint(CDC* pDC, CPrintInfo*)
    {
    ASSERT_VALID(pDC);
    OnDraw(pDC);   // CallDraw
    }

    既然OnPaint最后也要调用OnDraw,因此我们一般会在OnDraw函数中进行绘制。下面是一个典型的程序。
    ///视图中的绘图代码首先检索指向文档的指针,然后通过DC进行绘图调用。
    void CMyView::OnDraw( CDC* pDC )
    {

    CMyDoc*pDoc = GetDocument();
    CString s = pDoc->GetData();
    GetClientRect( &rect ); // Returns a CString CRectrect;
    pDC->SetTextAlign( TA_BASELINE | TA_CENTER);
    pDC->TextOut( rect.right / 2, rect.bottom / 2, s,s.GetLength() );
    }
    最后:现在大家明白这哥俩之间的关系了吧。因此我们一般用OnPaint维护窗口的客户区(例如我们的窗口客户区加一个背景图片),用OnDraw维护视 图的客户区(例如我们通过鼠标在视图中画图)。当然你也可以不按照上面规律来,只要达到目的并且没有问题,怎么干都成。补充:我们还可以利用 Invalidate(),ValidateRgn(),ValidateRect()函数强制的重画窗口,具体的请参考MSDN吧。

    参考网址:

      http://blog.csdn.net/thisispan/article/details/7408218

  • 相关阅读:
    无限维
    黎曼流形
    why we need virtual key word
    TOJ 4119 Split Equally
    TOJ 4003 Next Permutation
    TOJ 4002 Palindrome Generator
    TOJ 2749 Absent Substrings
    TOJ 2641 Gene
    TOJ 2861 Octal Fractions
    TOJ 4394 Rebuild Road
  • 原文地址:https://www.cnblogs.com/icmzn/p/5041438.html
Copyright © 2011-2022 走看看