|
(三)文档与视图之间的联系 在视图类有一个保护数据成员:cdocument* m_pdocument;,这个文档指针指向视图对象所属的文档,视图里常用的函数getdocument()就是返回的这个指针;在文档类有一个保护数据成员:cdocument* m_viewlist;,它保存的是所有正在显示该文档的视图的指针,通过cdocument的成员函数getfirstviewposition和getnextview函数可以实现对这些视图的访问。 在视图被创建的时候,在oncreate函数里视图和文档发生了关联: int cview::oncreate(lpcreatestruct lpcs) { if (cwnd::oncreate(lpcs) == -1) return -1; ccreatecontext* pcontext = (ccreatecontext*)lpcs->lpcreateparams;
if (pcontext != null && pcontext->m_pcurrentdoc != null) { pcontext->m_pcurrentdoc->addview(this); assert(m_pdocument != null); } else { trace0("warning: creating a pane with no cdocument.\n"); }
return 0; } 这个关联是通过文档类的addview函数实现的: void cdocument::addview(cview* pview) { …… m_viewlist.addtail(pview); pview->m_pdocument = this;
onchangedviewlist(); } 在这个函数里,首先文档对象先把所添加的视图指针加到自己的视图链表里,然后指向自己的指针赋給了所添加的视图的m_pdocument成员。 众所周知,文档与视图进行通信的方式先调用文档的updateallviews函数,从而调用视图的onupdate函数: void cdocument::updateallviews(cview* psender, lparam lhint, cobject* phint) // walk through all views { //视图链表不能为空且发送者不能为空 assert(psender == null || !m_viewlist.isempty()); position pos = getfirstviewposition(); while (pos != null) { cview* pview = getnextview(pos); assert_valid(pview); //不调用发送者的onupdate函数 if (pview != psender) pview->onupdate(psender, lhint, phint); } } 在视图的onupdate函数里默认的实现仅是通知视图进行重画: invalidate(true); 我们一般重载这个更新视图的某些数据或进行其他操作,比如更新视图滚动条的滚动范围。 (四)框架窗口与文档、视图之间的联系 在框架窗口被创建的时候,创建了视图,相关的函数如下: int cframewnd::oncreate(lpcreatestruct lpcs) { ccreatecontext* pcontext = (ccreatecontext*)lpcs->lpcreateparams; return oncreatehelper(lpcs, pcontext); } int cframewnd::oncreatehelper(lpcreatestruct lpcs, ccreatecontext* pcontext) { if (cwnd::oncreate(lpcs) == -1) return -1;
// create special children first if (!oncreateclient(lpcs, pcontext)) { trace0("failed to create client pane/view for frame.\n"); return -1; }
// post message for initial message string postmessage(wm_setmessagestring, afx_ids_idlemessage);
// make sure the child windows have been properly sized recalclayout();
return 0; // create ok } bool cframewnd::oncreateclient(lpcreatestruct, ccreatecontext* pcontext) { // default create client will create a view if asked for it if (pcontext != null && pcontext->m_pnewviewclass != null) { if (createview(pcontext, afx_idw_pane_first) == null) return false; } return true; } cwnd* cframewnd::createview(ccreatecontext* pcontext, uint nid) {
cwnd* pview = (cwnd*)pcontext->m_pnewviewclass->createobject(); if (pview == null) { return null; } assert_kindof(cwnd, pview);
if (!pview->create(null, null, afx_ws_default_view, crect(0,0,0,0), this, nid, pcontext)) { return null; // can't continue without a view }
if (afxdata.bwin4 && (pview->getexstyle() & ws_ex_clientedge)) { modifystyleex(ws_ex_clientedge, 0, swp_framechanged); } return pview; } 在文档模板的opendocumentfile函数发生了如下的调用: initialupdateframe(pframe, pdocument, bmakevisible); 文档模板的这个函数的实现为: pframe->initialupdateframe(pdoc, bmakevisible); 实际是调用了框架窗口的同名函数: void cframewnd::initialupdateframe(cdocument* pdoc, bool bmakevisible) { cview* pview = null; if (getactiveview() == null) { //取主视图 cwnd* pwnd = getdescendantwindow(afx_idw_pane_first, true); if (pwnd != null && pwnd->iskindof(runtime_class(cview))) { //主视图存在且合法,把当前的主视图设置为活动视图 pview = (cview*)pwnd; setactiveview(pview, false); } }
if (bmakevisible) { sendmessagetodescendants(wm_initialupdate, 0, 0, true, true);
if (pview != null) pview->onactivateframe(wa_inactive, this); …… activateframe(ncmdshow); if (pview != null) pview->onactivateview(true, pview, pview); }
// update frame counts and frame title (may already have been visible) if (pdoc != null)
本文关键:文档与视图的联系(三)
|