CWnd的派生类-2、CView类

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

然而,除了打印和打印预览外,视图类显得很简单。下面就从关联文档对象、绘制等几个方面进行阐述。

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

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

int CView::OnCreate(LPCREATESTRUCT lpcs)

{

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

                  return-1;

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

         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

         {

                  TRACE0("Warning: Creating a pane with no CDocument.\n");

         }

         return 0;   // ok

}

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

CDocument* CView::GetDocument() const

         { ASSERT(this != NULL); return m_pDocument; }

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

CView::~CView()

{        if (m_pDocument != NULL)

                  m_pDocument->RemoveView(this);

}

7.2.2  视图的绘制
窗口的绘制工作总是在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()。

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

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

{        ASSERT(pSender != this);

         UNUSED(pSender); // unused in release builds

         Invalidate(TRUE);

}

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

void CView::OnInitialUpdate()

{        OnUpdate(NULL, 0, NULL); }

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

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

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

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

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

         if (nAdjustType != 0)

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

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

                  DWORD dwStyle = GetStyle();

                  if (dwStyle & WS_VSCROLL)

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

                          int nAdjust = afxData.cxVScroll;

                          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);

}

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

void CView::PostNcDestroy()

{        delete this;}

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

7.2.7  虚函数virtual BOOL OnCmdMsg(UINT,
int, void*,AFX_CMDHANDLERINFO* )
在讨论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;

}

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

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

{        UNUSED(pActivateView);   // unused in release builds

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

         {        ASSERT(pActivateView == this);

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

                  if (IsTopParentActive())

                          SetFocus();

         }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值