分享
 
 
 

文档与视图的联系(三)

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

(三)文档与视图之间的联系

在视图类有一个保护数据成员: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)

pDoc->UpdateFrameCounts();

OnUpdateFrameTitle(TRUE);

}

上面的函数中对视图的操作主要是用SetActiveView设置了活动视图,并且调用了视图的OnActivateFrame函数。在CFrameWnd类中维护着一个保护成员:CView* m_pViewActive;,SetAcitveView函数主要就是对它进行操作:

void CFrameWnd::SetActiveView(CView* pViewNew, BOOL bNotify)

{

CView* pViewOld = m_pViewActive;

if (pViewNew == pViewOld)

return; // do not re-activate if SetActiveView called more than once

m_pViewActive = NULL; // no active for the following processing

// deactivate the old one

if (pViewOld != NULL)

pViewOld->OnActivateView(FALSE, pViewNew, pViewOld);

if (m_pViewActive != NULL)

return; // already set

m_pViewActive = pViewNew;

// activate

if (pViewNew != NULL && bNotify)

pViewNew->OnActivateView(TRUE, pViewNew, pViewOld);

}

CFrameWnd还有另一个函数返回这个成员:

CView* CFrameWnd::GetActiveView() const

{

ASSERT(m_pViewActive == NULL ||

m_pViewActive->IsKindOf(RUNTIME_CLASS(CView)));

return m_pViewActive;

}

CframeWnd还有一个函数能取得当前活动的文档,它是通过活动视图间接得到的:

CDocument* CFrameWnd::GetActiveDocument()

{

ASSERT_VALID(this);

CView* pView = GetActiveView();

if (pView != NULL)

return pView->GetDocument();

return NULL;

}

(五)MDI主窗口和子窗口之间的关联:

在MDI子窗口创建的时候,指定了它与MDI之间的关系:

BOOL CMDIChildWnd::Create(LPCTSTR lpszClassName,

LPCTSTR lpszWindowName, DWORD dwStyle,

const RECT& rect, CMDIFrameWnd* pParentWnd,

CCreateContext* pContext)

{

if (pParentWnd == NULL)

{

CWnd* pMainWnd = AfxGetThread()->m_pMainWnd;

ASSERT(pMainWnd != NULL);

ASSERT_KINDOF(CMDIFrameWnd, pMainWnd);

pParentWnd = (CMDIFrameWnd*)pMainWnd;

}

……

pParentWnd->RecalcLayout();

CREATESTRUCT cs;

……

//指定了所属的MDI子窗口

cs.hwndParent = pParentWnd->m_hWnd;

……

cs.lpCreateParams = (LPVOID)pContext;

if (!PreCreateWindow(cs))

{

PostNcDestroy();

return FALSE;

}

MDICREATESTRUCT mcs;

……

mcs.style = cs.style & ~(WS_MAXIMIZE | WS_VISIBLE);

mcs.lParam = (LONG)cs.lpCreateParams;

AfxHookWindowCreate(this);

//发送WM_MDICREATE消息,创建了MDI子窗口

HWND hWnd = (HWND)::SendMessage(pParentWnd->m_hWndMDIClient,

WM_MDICREATE, 0, (LPARAM)&mcs);

if (!AfxUnhookWindowCreate())

PostNcDestroy(); // cleanup if MDICREATE fails too soon

……

return TRUE;

}

当MDI子窗口创建了以后,MDI主窗口就可以用自己的函数实现对子窗口的管理,例如取得当前的活动子窗口是通过发送WM_MDIGETACTIVE消息实现的

作者Blog:http://blog.csdn.net/coordinate/

转自:http://dev.csdn.net/article/55/55362.shtm

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有