1.当与文档类关联的视图类收到文档类通过UpdateAllVIews()函数发出的更新重绘通知后,会触发视图类的OnUpdate()函数的实现(#add 观察者模式)。
UpdateAllVIews()的原型和特性:
Void UpdateAllVIews (CView* pSender, LPARAM lHint, CObject* pHint);
pSender: 指向修改该文档内部数据的视图(这样可以免去通知这个已经更新的视图重新更新)。
lHint: 包含关于修改的信息。
pHint: 指向一个存储关于具体描述修改信息的对象。
该函数有Document类对象调用,并告诉所有关联的视图文档的内部数据已经修改好,需要及时更新以实时反馈数据当前的状态。其中第一个参数是表示首先通过外部交互而改变内部数据的视图物件。因此,它的绘图应该是已经及时更新了的,这里指明它的作用在于,因为它可能是最新的了,所以在更新的时候,并不需要它做更新动作;而参数lHint和pHint是提示参数(Hint),它们会被传送到同一个Document类物件所关联的View视图中去(视图由OnUpdate()函数进行接收)。
在用到的几个参数中,lHint可以是一些特殊的提示值,pHint衍生值是CObject类对象的指针。这样做的原因是因为有时候通过某个视图修改某一块区域的标识会导致部分文档内部数据的修改,如果直接通知所有视图实现整个区域的重绘,会导致程序实现的效率非常低;所以这里就用一个提示,让每个关联的视图在更新的时候可以根据这些提示去重绘需要更新的部分就可以了。另外,由于这些提示对每个具体的实例程序都不一样,所以需要开发人员去定义这样的提示并在实际绘图中实现这些提示的目的功能。这样我们就可以理解为什么更新视图后,机制没有直接调用OnDraw()进行实际绘图更新,而在流程中途出现了OnUpdate()和Invalidate()等标志功能型的函数了。
接下来看看在视图View类对象里这个接收函数OnUpdate()的原型以及使用特性。
Virtual void OnUpdate (CView* pSender, LPARAM lHint, CObject* pHint);
该函数由CDocument::UpdateAllViews()呼叫产生,表示该文档内部数据已经被修改,通知相关的视图并更新图像。该函数的默认动作会利用流程中的Invalidate()函数将整个视图子区域置为无效,在收到WM_PAINT消息后对整个区域进行重绘。建议不对该函数做出任何直接的绘图动作,这里需要做的是确定整个无效的矩形区域,并传递这个矩形区域给CWnd::InvalidateRect()函数,通知该计算出来的矩形区域无效。而InvalidateRect()函数会触发WM_PAINT函数通知重绘。当lHint为0,且pHint的值为NULL的时候,表示文档类对象已经暗示整个总体绘图区域无效,这时候需要重绘,而其他情况,需要根据自己定义的方式去解读该无效区域是什么,然后在实际的绘图函数中实现对该区域的重绘处理。
把上面的描述综合起来概括就是,视图文档的OnUpdate()函数完全接受更新后的UpdateAllViews()函数的所有参数,根据这些参数的提示去计算最小、最适当的视图重绘矩形区域,然后调用InvalidateRect()函数宣布该矩形区域无效,从而引发绘图的更新实现。当然,如果不去设置以及计算具体的重绘区域,那么,就可以不对这个OnUpdate()函数重写了,它的默认处理方法是通知整个视图绘图子区域无效,实现所有区域的重绘。
2.下面三个函数与窗口重绘中的无效矩形有关:
InvalidateRect() :产生无效矩形,并生成WM_PAINT消息。
ValidateRect() :使无效矩形区有效。
GetUpdateRect() :获得无效矩形坐标(逻辑)。
当调用文档的UpdateAllViews()时,框架会自动调用OnUpdate()函数,也可以在视图类中直接调用该函数。OnUpdate()函数一般是这样处理的:先访问文档,读取文档的数据,然后对视图的数据成员或控制进行更新,以反应文档的改动。可以用OnUpdate()函数使视图的某部分无效,以便触发式的OnDraw()利用文档数据重绘窗口。缺省的OnUpdate()使窗口的整个客户区都无效,在重新设计时,要利用提示信息lHint和pHint定义一个较小的无效矩形。
Void InvalidateRect(LPCRECT lpRect, BOOL bErase = TRUE);
然后在OnDraw()中,将根据无效矩形绘制图形,而不是重绘全部笔划。
在OnDraw()中可以调用GetClipBox()取得当前被剪裁区域(无效矩形区域),它把矩形复制到GetClipBox()的参数rectClip中。
3.鼠标消息捕获函数:
CWnd::SetCapture(); 用于捕获鼠标信息,无论光标位置在何处,都会将鼠标消息送给调用它的那一个窗口。
CWnd::GetCapture ();
CWnd::ReleaseCapturer(); 释放窗口对鼠标的控制,否则其他窗口将无法接收到鼠标消息。