CView

CView编辑

本词条缺少 信息栏名片图,补充相关内容使词条更完整,还能快速升级,赶紧来 编辑吧!
CView是视图程序设计中使用率最高的 窗口对象,它是用户的主要操作界面。因为它通常以某种形式表示文档数据,所以称之为视图。一个视图对象只关联一个文档对象;一个文档对象可以关联多个视图,每个视图对象以不同形式表示文档数据。

1简介编辑

从文档类中将文档中的数据取出后显示给用户;接受用户对文档中数据的编辑和修改;将修改的结果反馈给文档类,由文档类将修改后的内容保存到磁盘文件中。
文档负责了数据真正在永久介质中的存储和读取工作,视图呈现只是将文档中的数据以某种形式向用户呈现,因此一个文档可对应多个视图。
Invalidate(TRUE)将整个窗口设置为需要重绘的无效区域,它会产生WM_PAINT消息,这样OnDraw将被调用。
假如文档中的数据发生了变化,必须通知所有链接到该文档的视图,这时候文档类的UpdateAllView函数需要被调用。
然而,除了打印和打印预览外,视图类显示得很简单。

2关联对象编辑

前面已经提到,视图需要表示文档数据,所以文档对象与视图对象必须建立关联。这样,当文档数据发生变化时,它可以及时通知视图;当视图需要显示不同的文档数据时,它可以从文档对象中提取。
在文档/视图框架程序中,文档对象总是在视图之前建立,而在视图的WM_CREATE消息处理函数中,建立了它与文档对象的关联。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
IntCView::OnCreate(LPCREATESTRUCTlpcs)
{
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:CreatingapanewithnoCDocument.\n”);
}
return0; //ok
}
同时,视图类定义了成员函数GetDocument(),返回文档对象的指针。代码如下:
1
2
3
4
5
CDocument*CView::GetDocument() const
{
ASSERT( this !=NULL);
returnm_pDocument;
}
视图总是在文档对象之前销毁,在视图的 析构函数中,与文档对象解除关联。代码如下:
1
2
3
4
5
CView::~CView()
{
if (m_pDocument!=NULL)
m_pDocument->RemoveView( this );
}

3视图绘制编辑

窗口的绘制工作总是在WM_PAINT消息处理中进行的,当窗口需要绘制时,它会收到系统发来的WM_PAINT消息。在绘制过程中,首先要准备显示设备句柄,最后要释放句柄。众所周知,在视图窗口中绘制,无需重载WM_PAINT消息处理函数OnPaint(),因为有一个更加友好的绘制新口:OnDraw()。该函数的实参是一个已经准备好的显示设备,最后无需释放。其实,这一切还是WM_PAINT消息处理函数OnPaint()为我们准备的,代码如下:
1
2
3
4
5
6
7
voidCView::OnPaint()
{
//CPaintDC类维护显示设备
CPaintDCdc( this );
OnPrepareDC(&dc);
OnDraw(&dc);
}
OnPrepareDC()是一个 虚拟函数,它总是在OnDraw()之前执行,可以重载它,设置绘图模式。因为OnDraw()每次执行,都使用不同的CPaintDC对象,所以本次绘图模式的状态不能保留到下一次。
OnDraw()在视图基类CView中定义为 纯虚函数。例如:
1
virtualvoidOnDraw(CDC*pDC)=0;
所以CView是抽象基类,不能实例化,而 派生类必须重载OnDraw()。

4虚函数编辑

OnUpdate

当文档数据发生变化时,文档对象调用CDocument::UpdateAllView()通知所有视图,作为响应,视图的OnUpdate()成员被调用。所以,重载的OnUpdate()应该能够根据需要,将文档数据的变化反映在视图中。CView::OnUpdate()只是简单地使客户区无效,导致客户区重画。例如:
1
2
3
4
5
6
voidCView::OnUpdate(CView*pSender, LPARAM ,CObject*)
{
ASSERT(pSender!= this );
UNUSED(pSender); //unusedinreleasebuilds
Invalidate(TRUE);
}

OnInitialUpdate()

在初始创建、调用OnCreate()之后,或者在File/New、File/Open命令后被 框架调用。基类CView:: OnInitialUpdate()只是简单地调用OnUpdate(),可以重载它完成初始化工作。但注意,它可能被多次调用。
1
2
3
4
voidCView::OnInitialUpdate()
{
OnUpdate(NULL,0,NULL);
}CalcWindowRect
每当主框架窗口的客户区尺寸发生变化或 控制条的位置发生变化,需要重新排列客户区时,调用该函数,根据视图客户区尺寸计算视图窗口的尺寸。
我们知道,排列主窗口客户区是由CFrameWnd::RecalcLayout()完成的。显然,视图的CalcWindowRect()函数也是由它触发调用的。主窗口的客户区尺寸减掉所有控制占用的部分,剩下的区域分给视图,这部分区域作为实参传入CalcWindowRect()。在CalcWindowRect()函数内,需要计算视图窗口的尺寸。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
voidCView::CalcWindowRect(LPRECTlpClientRect,UNITnAdjustType)
{
//lpClientRect此时是整个视图客户区的尺寸
//需要为滚动条增加尺寸吗
if (nAdjustType!=0)
{
//调用API,根据窗口风格计算窗口尺寸
::AdjustWindowRectEx(lpClientRect,0,FALSE,GetExStyle());
DWORDdwStyle=GetStyle();
if (dwStyle&WS_VSCROLL)
{
//为垂直滚动条增加尺寸
//afxData在.NET下需要#include<../../src/mfc/afximpl.h>
//afxData在VC6.0下需要#include<../src/mfc/afximpl.h>
 
intnAdjust=afxData.cxVScroll;
if (dwStyle&WS_BORDER)
nAdjust-=CX_BORDER;
lpClientRect->right+=nAdjust;
}
if (dwStyle&WS_HSCROLL)
{
//为水平滚动条增加尺寸
intnAdjust=afxData.cyHScroll;
if (dwStyle&WS_BORDER)
nAdjust-=CY_BORDER;
lpClientRect->bottom+=nAdjust;
}
return ;
}
//无需为滚动条增加尺寸,调用基类成员完成计算
CWnd::CalcWindowRect(lpClientRect,nAdjustType);
}

PostNcDestroy

在视图窗口关闭时最后调用的成员函数,它与CFrameWnd::PostNcDestroy完成相同的功能,即删除视图对象。代码如下:
1
2
3
4
voidCView::PostNcDestroy()
{
deletethis;
}
这样,可以不必关心视图的释放工作,即使它在堆中构造。

OnCmdMsg

在讨论CFrameWnd::OnCmdMsg()时已经了解过该函数,下面只给出它的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
BOOLCView::OnCmdMsg(UINTnID,intnCode, void *pExtra,AFX_CMDHANDLERINFO*pHandlerInfo)
{
//首先查找自身的命令消息映射
if (CWnd::OnCmdMsg(nID,nCode,pExtra,pHandlerInfo))
returnTRUE;
//如果视图本身没有处理该命令,将机会留给与其关联的文档对象
if (m_pDocument!=NULL)
{
CPushRoutingViewpush( this );
returnm_pDocument->OnCmdMsg(nID,nCode,pExtra,pHandlerInfo);
}
returnFALSE;
}

OnActivateView

当视图被激活为活动视图,或由活动转为非活动时,调用该函数通知视图。基类的实现只是设置该视图为焦点。代码如下:
1
2
3
4
5
6
7
8
9
10
11
voidCView::OnActivateView(BOOLbActivate,CView*pActivateView,CView*)
{
UNUSED(pActivateView); //unusedinreleasebuilds
if (bActivate) //当前状态为活动吗
{
ASSERT(pActivateView== this );
//如果其父窗口也是活动的,则设置焦点。(在MDI中,其父框架可能是非活动的)
if (IsTopParentActive())
SetFocus();
}
}

5派生类编辑

MFC提供了丰富的CView派生类,各种不同的派生类实现了对不同种类控件的支持,以为用户提供多元化的显示界面。
1
2
3
4
5
6
7
8
9
CScrollView:提供滚动支持;
CCtrlView:支持tree、list和richedit控件;
CDaoRecordView:在dialog-box控件中显示数据库记录;
CEditView:提供了一个简单的多行文本编辑器视图;
CFormView:包含dialog-box控件,可滚动,基于对话框模板资源;
CListView:支持列表控件视图;
CRecordView:在dialog-box控件中显示数据库记录;
CRichEditView:支持富文本编辑的控件视图;
CTreeView:支持重点在树控件的文档/视图结构的视图。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值