C++ Q&A...
更新MFC中的视图,跟踪.NET Framework中的事件
原著:Paul DiLascia
翻译:肖进
如何更新MFC中的视图? 如何跟踪.NET Framework 中的事件?
原文出处:MSDN Magazine May 2004(C++ Q&A)
下载源代码 CQA0405.exe(198KB)
我在 MDI 程序中打算通过 CMainFrame 中的定时器事件来更新所有的子窗口。 视图用于显示许多图表。用如下的代码只能更新当前活动窗口:
GetActiveWindow()-GetActiveView()-GetDocument()
是否有其它的方法从 CMDIFrame 类中获得所有的子窗口或者所有的文档?
Makarand 你的情况并不罕见。许多采集实时数据的程序需要定时更新屏幕。即使你的程序不是采集实时数据,当用户的操作改变文档时,你一样要更新视图。MFC中doc/view模型(包括所有的object/view模型)的基本思想是数据与显示的分离。用户或者 实际事件改变了底层对象、数据或者文档,就会通过某些视图立即更新事件传递给显示机制。
对于同一个文档如果有数个视图,MFC已经有了一种机制一步到位地更新所有视图。这个函数就是CDocument::UpdateAllViews,它对打开文档的每 一个视图调用 CView::OnUpdate。你可以传递应用程序专用的,描述要执行哪一种更新操作的“提示”。例如,如果你知道仅仅是文档的标题改变了,你就可以定义一个枚举值 CHANGED_TITLE,将它作为 提示代码进行传递。如果你的文档包含了图片和文字,你可以定义枚举值 CHANGED_TEXT 和 CHANGED_GRAPHICS。这些 提示代码的目的是提高性能。通过“提示”来告诉视图什么东西改变了,这样就可以更智能地只重绘那些真正需要刷新的屏幕区域,从而避免潜在的耗时的绘制操作或屏幕闪烁。
UpdateAllViews 更新所有与某个文档关联的视图,但是如何更新所有的文档呢?MFC中没有UpdateAllDocuments 这样的函数,因此你需要自己列举所有的文档。这 就要求实现一个对文档模板和相关文档的循环操作,如下所示:
for (/* each CDocTemplate in app */) {for (/* each CDocument in CDocTemplate */) {// do something}}
既然列举文档是如此的有用,我写了一个很小的类 CDocEnumerator,隐藏了MFC中所有的模板和位置的机制。 实际上,这个类是我早在1995年9月写的——呵呵,这都几乎是十年前的事了。代码如 Figure 1 所示。 使用 CDocEnumerator 很容易在程序中列举所有打开的文档。
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/cyuyanjiaocheng/)CDocEnumerator it;CDocument* pdoc;while ((pdoc=it.Next())!=NULL) {// do something}
还有什么比这个更容易?为了在实际的例子中示范这个类的用法,我写了一个小程序 UpdView,该程序将模拟实时数据采集程序。UpdView 中每个文档对其打开的秒数进行计数。Figure 2 显示了工作中的 UpdView。如果下载、生成并运行 UpdView,你便能看到每个视图每秒更新显示文档打开的秒数。在 Figure 2 中,名字为 file2.dat 的文档有两个视图,它们都显示同一个底层文档。每个文档维持自己的自打开后的时间数(数据),视图只是进行显示(表现)。在你自己的程序中,UpdView通过主框架的定时器设置工作。这个定时器处理事件使用 CDocEnumerator 告诉每一个文档收集更多的数据,如下面所示:
void CMainFrame::OnTimer(UINT_PTR nIDEvent) { CDocEnumerator it; CDocument* pdoc; while ((pdoc=it.Next())!=NULL) { ((CMyDoc*)pdoc)->CollectMoreData(); }}
Figure 2 运行中的UpdView
CMyDoc::CollectMoreData 增加了一个简单计数器的值。在一个实时程序中,CMyDoc::CollectMoreData 将获得最新的数据,如下载最近的火星图片,或者读取 Bill Gates 浴缸的温度。重要的采集数据后,CMyDoc 通知它的视图自动更新:
void CMyDoc::CollectMoreData() { iData++; // time waits for no man... UpdateAllViews(NULL, 0, NULL);}现在,MFC 调用每个视图的 OnUpdate 方法,再调用 Invalidate/UpdateWindow 刷新视图。既然UpdView 是如此的简单,就没有必要提示了。在一个实际的程序中,你 可能需要传递提示信息来帮助视