分享
 
 
 

CView

王朝百科·作者佚名  2010-04-29
窄屏简体版  字體: |||超大  

视图是程序设计中使用率最高的窗口对象,它是用户的主要操作界面。因为它通常以某种形式表示文档数据,所以称之为视图。一个视图对象只关联一个文档对象;一个文档对象可以关联多个视图,每个视图对象以不同形式表示文档数据。

从文档类中将文档中的数据取出后显示给用户;接受用户对文档中数据的编辑和修改;将修改的结果反馈给文档类,由文档类将修改后的内容保存到磁盘文件中。

文档负责了数据真正在永久介质中的存储和读取工作,视图呈现只是将文档中的数据以某种形式向用户呈现,因此一个文档可对应多个视图。

Invalidate(TRUE)将整个窗口设置为需要重绘的无效区域,它会产生WM_PAINT消息,这样OnDraw将被调用。

假如文档中的数据发生了变化,必须通知所有链接到该文档的视图,这时候文档类的UpdateAllView函数需要被调用。

然而,除了打印和打印预览外,视图类显示得很简单。

关联文档对象前面已经提到,视图需要表示文档数据,所以文档对象与视图对象必须建立关联。这样,当文档数据发生变化时,它可以及时通知视图;当视图需要显示不同的文档数据时,它可以从文档对象中提取。

在文档/视图框架程序中,文档对象总是在视图之前建立,而在视图的WM_CREATE消息处理函数中,建立了它与文档对象的关联。代码如下:

Int CView::OnCreate (LPCREATESTRUCT lpcs)

{

if (CWnd::OnCreate(lpcs) == -1)

return -1;

// m_pDocuemnt视图成员,用于存储相应文档对象的指针,此时为空

ASSERT(m_pDocument == NULL);

CCreateContext* pContext = (CCreateContext*)lpcs->lpCreateParams;

// pContext->m_pCurrentDoc是已经建立的文档对象的指针

if (pContext != NULL && pContext->m_pCurrentDoc != NULL)

{

// 将当前视图加入文档对象的视图列表中,因为一个文档可关联多个视图

pContext->m_pCurrentDoc->AddView(this);

/* 在文档的AddView()函数中,已经将当前文档对象指针赋给m_pDocument视图成员。这样,在视图建立之初,二者就建立了关联。*/

ASSERT(m_pDocument != NULL);

}

else

{

TRACE(“Warning: Creating a pane with no CDocument.

”);

}

return 0; // ok

}

同时,视图类定义了成员函数GetDocument(),返回文档对象的指针。代码如下:

CDocument* CView::GetDocument() const

{

ASSERT(this != NULL);

return m_pDocument;

}

视图总是在文档对象之前销毁,在视图的析构函数中,与文档对象解除关联。代码如下:

CView::~CView()

{

if (m_pDocument != NULL)

m_pDocument->RemoveView(this);

}

视图的绘制窗口的绘制工作总是在WM_PAINT消息处理中进行的,当窗口需要绘制时,它会收到系统发来的WM_PAINT消息。在绘制过程中,首先要准备显示设备句柄,最后要释放句柄。众所周知,在视图窗口中绘制,无需重载WM_PAINT消息处理函数OnPaint(),因为有一个更加友好的绘制新口:OnDraw()。该函数的实参是一个已经准备好的显示设备,最后无需释放。其实,这一切还是WM_PAINT消息处理函数OnPaint()为我们准备的,代码如下:

void CView::OnPaint()

{

// CPaintDC类维护显示设备

CPaintDC dc(this);

OnPrepareDC(&dc);

OnDraw(&dc);

}

OnPrepareDC()是一个虚拟函数,它总是在OnDraw()之前执行,可以重载它,设置绘图模式。因为OnDraw()每次执行,都使用不同的CPaintDC对象,所以本次绘图模式的状态不能保留到下一次。

OnDraw()在视图基类CView中定义为纯虚函数。例如:

virtual void OnDraw(CDC* pDC) = 0;

所以CView是抽象基类,不能实例化,而派生类必须重载OnDraw()。

虚函数 OnUpdate当文档数据发生变化时,文档对象调用CDocument::UpdateAllView()通知所有视图,作为响应,视图的OnUpdate()成员被调用。所以,重载的OnUpdate()应该能够根据需要,将文档数据的变化反映在视图中。CView::OnUpdate()只是简单地使客户区无效,导致客户区重画。例如:

void CView::OnUpdate(CView* pSender, LPARAM, CObject*)

{

ASSERT(pSender != this);

UNUSED(pSender); // unused in release builds

Invalidate(TRUE);

}

虚函数 OnInitialUpdate()在初始创建、调用OnCreate()之后,或者在File/New、File/Open命令后被框架调用。基类CView::OnInitialUpdate()只是简单地调用OnUpdate(),可以重载它完成初始化工作。但注意,它可能被多次调用。

void CView::OnInitialUpdate()

{

OnUpdate(NULL, 0, NULL);

}

虚函数 CalcWindowRect每当主框架窗口的客户区尺寸发生变化或控制条的位置发生变化,需要重新排列客户区时,调用该函数,根据视图客户区尺寸计算视图窗口的尺寸。

我们知道,排列主窗口客户区是由CFrameWnd::RecalcLayout()完成的。显然,视图的CalcWindowRect()函数也是由它触发调用的。主窗口的客户区尺寸减掉所有控制占用的部分,剩下的区域分给视图,这部分区域作为实参传入CalcWindowRect()。在CalcWindowRect()函数内,需要计算视图窗口的尺寸。代码如下:

void CView::CalcWindowRect(LPRECT lpClientRect, UNIT nAdjustType)

{

// lpClientRect此时是整个视图客户区的尺寸

// 需要为滚动条增加尺寸吗

if (nAdjustType != 0)

{

// 调用API,根据窗口风格计算窗口尺寸

::AdjustWindowRectEx(lpClientRect, 0, FALSE, GetExStyle());

DWORD dwStyle = GetStyle();

if (dwStyle & WS_VSCROLL)

{

// 为垂直滚动条增加尺寸

int nAdjust = afxData.csVScroll;

if (dwStyle & WS_BORDER)

nAdjust -= CX_BORDER;

lpClientRect->right += nAdjust;

}

if (dwStyle & WS_HSCROLL)

{

// 为水平滚动条增加尺寸

int nAdjust = afxData.cyHScroll;

if (dwStyle & WS_BORDER)

nAdjust -= CY_BORDER;

lpClientRect->bottom += nAdjust;

}

return;

}

// 无需为滚动条增加尺寸,调用基类成员完成计算

CWnd::CalcWindowRect(lpClientRect, nAdjustType);

}

虚函数PostNcDestroy在视图窗口关闭时最后调用的成员函数,它与CFrameWnd::PostNcDestroy完成相同的功能,即删除视图对象。代码如下:

void CView::PostNcDestroy()

{

delete this;

}

这样,可以不必关心视图的释放工作,即使它在堆中构造。

虚函数OnCmdMsg在讨论CFrameWnd::OnCmdMsg()时已经了解过该函数,下面只给出它的代码:

BOOL CView::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)

{

// 首先查找自身的命令消息映射

if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))

return TRUE;

// 如果视图本身没有处理该命令,将机会留给与其关联的文档对象

if (m_pDocument != NULL)

{

CPushRoutingView push(this);

return m_pDocument->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);

}

return FALSE;

}

虚函数 OnActivateView当视图被激活为活动视图,或由活动转为非活动时,调用该函数通知视图。基类的实现只是设置该视图为焦点。代码如下:

void CView::OnActivateView(BOOL bActivate, CView* pActivateView, CView*)

{

UNUSED(pActivateView); // unused in release builds

if (bActivate) // 当前状态为活动吗

{

ASSERT(pActivateView == this);

// 如果其父窗口也是活动的,则设置焦点。(在MDI中,其父框架可能是非活动的)

if (IsTopParentActive())

SetFocus();

}

}

MFC中丰富的CView派生类MFC提供了丰富的CView派生类,各种不同的派生类实现了对不同种类控件的支持,以为用户提供多元化的显示界面。

CScrollView: 提供滚动支持;

CCtrlView: 支持tree、list和rich edit控件;

CDaoRecordView: 在dialog-box控件中显示数据库记录;

CEditView: 提供了一个简单的多行文本编辑器视图;

CFormView: 包含dialog-box控件,可滚动,基于对话框模板资源;

CListView: 支持列表控件视图;

CRecordView: 在dialog-box控件中显示数据库记录;

CRichEditView: 支持富文本编辑的控件视图;

CTreeView: 支持重点在树控件的文档/视图结构的视图。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
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- 王朝網路 版權所有