Document/View是MFC的基石,负责程序数据的管理和显示,Doculent和Viewd的关系有一档一视,一档多视和多档多视,下面将分别对实现过程中的重点知识进行总结。
  1. 视图的同步更新
  2. 序列化和反序列化
  3. 双缓存绘图
  4. CSplitterWnd视图切割
  5. 映射模式(SetMapMode)
  6. 使用CMDIFrameWnd::OnWindowNew实现多视图显示
  7. 多重文件类型

1. 视图的同步更新

  UpdateAllViews----->OnUpDate----->WM_PAINT------->OnDraw

  UpdateAllView(NULL) 表示更新所有视图

  同时也可以根据UpdateAllViews中的第二个第三个参数实现只更新需要重绘区域,提高效率

  UpdateAllViews源码如下:

void CDocument::UpdateAllViews(CView* pSender, LPARAM lHint, CObject* pHint)
// walk through all views
{
ASSERT(pSender == NULL || !m_viewList.IsEmpty());
// must have views if sent by one of them POSITION pos = GetFirstViewPosition();
while (pos != NULL)
{
CView* pView = GetNextView(pos);
ASSERT_VALID(pView);
if (pView != pSender)
pView->OnUpdate(pSender, lHint, pHint);
}
}

  重载OnUpdate,实现无效区域重绘代码

void CScribbleView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
{
// TODO: 在此添加专用代码和/或调用基类
if (pHint != NULL)
{
if (pHint->IsKindOf(RUNTIME_CLASS(CStroke)))
{
CStroke *pStroke = (CStroke *)pHint;
CClientDC dc(this);
OnPrepareDC(&dc);
CRect rectInvalid = pStroke->GetBoundingRect();
dc.LPtoDP(&rectInvalid);
InvalidateRect(&rectInvalid);
return;
}
}return;
}

  OnDraw关键代码

void CScribbleView::OnDraw(CDC* pDC)
{
CScribbleDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return; // 得到窗口的无效区域
CRect rectClip;
pDC->GetClipBox(&rectClip);
  // 得到已变化的区域
  rectStroke = pStroke->GetBoundingRect();
  // 判断两区域是否有交集,有则更新视图
  if (!rectStroke.IntersectRect(&rectStroke, &rectClip)){continue;}
}

2. 序列化和反序列化

  Serialize机制作为MFC六大关键技术之一,实现对象、资料的序列化和反序列化

  所有派生于CObject的类都拥有RunTimeClass、IsKindof和IsSerialBle功能,Serialize机制的具体实现这里不作说明,只介绍如何使用。

  继承于CObject的类若要具备Serialize机制需具备以下条件:

  (1)类必须要有默认的无参数构造函数

  (2)类的声明中添加DECLARE_SERIAL(CNewClass)

  (3) 类的实现中添加IMPLEMENT_SERIAL(CNewClass, CObject, 1),注意第三个参数为版本号,版本号如为0XFFFF,则无Serialize

  (4) 类中重载Serialize(CArchive &ar)虚函数

void CStroke::Serialize(CArchive &ar)
{
if (ar.IsStoring()) // 写文件
{
ar << a;
}
else  // 读文件
{
ar >> a;
}
}

3. 双缓存绘图,防止闪烁

(1)在OnDraw函数中创建内存DC,在内存DC上绘图,然后再将内存DC通过BitBlt或StrechBlt贴到原DC上

(2)重写OnEraseBkgnd虚函数,return TRUE;

CRect rc;
GetClientRect(&rc);
CDC MemDC;
MemDC.CreateCompatibleDC(pDC);
CBitmap BitMap;
BitMap.CreateCompatibleBitmap(pDC,rc.Width(),rc.Height());
CBitmap* pOldBitMap = MemDC.SelectObject(&BitMap);
MemDC.FillSolidRect(rc, pDC->GetBkColor());
.....绘图
pDC->BitBlt(,,rc.Width(),rc.Height(), &MemDC,,,SRCCOPY);
MemDC.DeleteDC();
BitMap.DeleteObject();
BOOL CScribbleView::OnEraseBkgnd(CDC* pDC)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//return CView::OnEraseBkgnd(pDC);
return TRUE;
}

4. CSplitterWnd视图切割

(1)视图创建过程

  从MFC源码看出View产生的整个流程如下:

  OpenDocumentFile----->CreateNewDocument----->CreateNewFrame----->LoadFrame

  LoadFrame的最后一个参数为CCreateContext

struct CCreateContext   // Creation information structure
// All fields are optional and may be NULL
{
// for creating new views
CRuntimeClass* m_pNewViewClass; // runtime class of view to create or NULL
CDocument* m_pCurrentDoc; // for creating MDI children (CMDIChildWnd::LoadFrame)
CDocTemplate* m_pNewDocTemplate; // for sharing view/frame state from the original view/frame
CView* m_pLastView;
CFrameWnd* m_pCurrentFrame; // Implementation
CCreateContext();
};

  Document Frame窗口产生之际由于WM_CREATE的发生导致

  CFrameWnd::OnCreate------>CFrameWnd::OnCreateHelper----->CFrameWnd::OnCreateClient----->CFrameWnd::CreateView

(2)视图切割

  由上我们看出视图的产生在虚函数OnCreateClient中,所以进行视图的切割操作应在该函数中发生

// 重写OnCreateClient虚函数,创建视图
BOOL CChildFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
m_wndSplit1.CreateStatic(this, , );
m_wndSplit1.CreateView(,,RUNTIME_CLASS(CTextView), CSize(, ), pContext); m_wndSplit2.CreateStatic(&m_wndSplit1, , , WS_CHILD|WS_VISIBLE, m_wndSplit1.IdFromRowCol(,));
m_wndSplit2.CreateView(, , RUNTIME_CLASS(CBarView), CSize(, ), pContext);
//m_wndSplit2.CreateView(1, 0, RUNTIME_CLASS(CGraphView), CSize(0, 0), pContext); // 为了不添加CGraphView头文件引起编译错误
m_wndSplit2.CreateView(, , pContext->m_pNewViewClass, CSize(, ), pContext); SetActiveView((CView* )m_wndSplit1.GetPane(,));
return TRUE;
}

5. 映射模式(SetMapMode)

  具体的映射模式种类可以百度或参考映射模式之SetMapMode,下面只是总结SetMapMode(MM_ANISOTROPIC)的使用,使用MM_ANISOTROPIC并结合SetWindoworg、SetViewportorg、SetWindowExt和SetViewportExt我们可以自定义坐标系(比例和方向)

CRect rc;
GetClientRect(&rc);
// 设置坐标系
pDC->SetMapMode(MM_ANISOTROPIC);
// 设置窗口原点
pDC->SetWindowOrg(, );
// 对应视口的右下角
pDC->SetViewportOrg(rc.left + , rc.bottom - );
pDC->SetWindowExt(, );
pDC->SetViewportExt(rc.Width()- , -(rc.Height() - ));

  上面代码将CSize(100,100)映射到(rc.Width()- 40, -(rc.Height() - 40)上,坐标系如下:

  将逻辑坐标转换为设备坐标:LPtoDP

  将设备坐标转换为逻辑坐标:DPtoLP

6. 使用CMDIFrameWnd::OnWindowNew实现多视图显示

  如果你不喜欢分裂窗口,我们可以来点新鲜的,重写OnWindowNew函数

(1)添加新的CMultiDocTemplate

m_pTemplateTxt= new CMultiDocTemplate(IDR_TextTYPE,
RUNTIME_CLASS(CTextDoc),
RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架
RUNTIME_CLASS(CTextView));

m_pTemplateHex = new CMultiDocTemplate(IDR_TextTYPE,
      RUNTIME_CLASS(CTextDoc),
      RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架
      RUNTIME_CLASS(CHexView));

(2)添加菜单项进行视图创建测试

void CMainFrame::OnTesta()
{
CMDIChildWnd *pActiveChild= MDIGetActive();
CDocument *pDocument;
if (pActiveChild == NULL
|| (pDocument = pActiveChild->GetActiveDocument()) == NULL)
{
return;
} CDocTemplate *pTemplate = ((CTextApp *)AfxGetApp())->m_pTemplateTxt;
if (pTemplate == NULL)
{
return;
} CFrameWnd *pFrame = pTemplate->CreateNewFrame(pDocument, pActiveChild);
if (pFrame == NULL)
{
return;
} pTemplate->InitialUpdateFrame(pFrame, pDocument);
}
// 关键点:重写CMDIFrameWnd::OnWindowNew创建视图
void CMainFrame::OnTest01()
{
CMDIChildWnd *pActiveChild = MDIGetActive();
CDocument *pDocument;
if (pActiveChild == NULL
|| (pDocument = pActiveChild->GetActiveDocument()) == NULL)
{
return;
} CDocTemplate *pTemplate = ((CTextApp *)AfxGetApp())->m_pTemplateHex;
if (pTemplate == NULL)
{
return;
} CFrameWnd *pFrame = pTemplate->CreateNewFrame(pDocument, pActiveChild);
if (pFrame == NULL)
{
return;
} pTemplate->InitialUpdateFrame(pFrame, pDocument);
}

(3)效果如下

7. 多重文件类型

  以下为在多文档视图中实现多文档类型:

(1)添加新建UI系统

CMultiDocTemplate(UINT nIDResource,CRuntimeClass* pDocClass,

CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass);

  nIDResource是一个资源ID,表示此一文件类型(文件格式)所使用的资源。内容都在.rc文件中,包含ICON/MENU等等信息,可以自己查看

(2)添加新DOC

(3)添加新View,添加相应显示内容

(4)添加CMultiDocPlate

pDocTemplate = new CMultiDocTemplate(IDR_NEWTYPE,
RUNTIME_CLASS(CNewDoc),
RUNTIME_CLASS(CMDIChildWnd), // 自定义 MDI 子框架
RUNTIME_CLASS(CNewDocView));
if (!pDocTemplate)
return FALSE;
AddDocTemplate(pDocTemplate);

(5)效果

上述内容代码链接:https://pan.baidu.com/s/117eij5osBlopdjVdUbXT1A,纯为测试代码!

MFC之document与view实践总结的更多相关文章

  1. Android显示框架:自定义View实践之绘制篇

    文章目录 一 View 二 Paint 2.1 颜色处理 2.2 文字处理 2.3 特殊处理 三 Canvas 3.1 界面绘制 3.2 范围裁切 3.3 集合变换 四 Path 4.1 添加图形 4 ...

  2. MFC + XToolKit的使用 ( 亲自实践 )

    1. 变量声明: 在Dlg.h    的public下 CXTPButton m_Button2; 2. 变量交换并设置按钮风格: Dlg.cpp下 void CXT_VS2010Dlg::DoDat ...

  3. 深入分析MFC文档视图结构(项目实践)

    k_eckel:http://www.mscenter.edu.cn/blog/k_eckel 文档视图结构(Document/View Architecture)是MFC的精髓,也是Observer ...

  4. MFC笔记

    一.Win32基本程序概念 所有的windows程序都必须载入windows.h MFC程序都有一个Stdafx.h文件,它载入了MFC框架必须的文件. Windows程序以消息为基础,以事件驱动之. ...

  5. 深入浅出MFC——Document-View深入探讨(五)

    1. MFC之所以为Application Framework,最重要的一个特征就是它能够将管理数据的程序代码和负责数据显示的程序代码分离开来,这种能力由MFC的Document/View提供.Doc ...

  6. 【笔记】《深入浅出MFC》第5章 总观Application Framework

    凝聚性强.组织化强的类库就是Application Framework.一组合作无间的对象,彼此藉消息的流动而沟通,并且互相调用对方的函数以求完成任务,这就是Application Framework ...

  7. 关于获得MFC窗口其它类指针的方法(csdn)

    转自:http://tieba.baidu.com/p/252804018 访问应用程序的其它类 获得CWinApp: -在CMainFrame,CChildFrame,CDocument,CView ...

  8. 《深入浅出MFC》– Document-View深入探讨

    1.其实Document/View不是什么新东西,Xerox PARC实验室是这种观念的滥觞.它是Smalltalk环境中的关键性部分,在那里它被称为Model-View-Controller(MVC ...

  9. MFC深入浅出读书笔记第三部分1

    第八章 Document-View 深入探讨(总结) 1.Document Document 在MFC 的CDocument 里头被具体化.CDocument 本身并无任何具体数据,它只是提供一个空壳 ...

随机推荐

  1. [JSOI2016]反质数序列

    我竟然半个小时切了一道JSOI2016,,,,不敢相信. 首先可以发现,如果N个数中1出现的次数<=1的话,我们按不能在一个集合连无向边的话,连出的一定是一个二分图. 接下来我来证明一下: 因为 ...

  2. scrapy的allowed_domains设置含义

    设置allowed_domains的含义是过滤爬取的域名,在插件OffsiteMiddleware启用的情况下(默认是启用的),不在此允许范围内的域名就会被过滤,而不会进行爬取 但是有一个问题:像下面 ...

  3. ImportError: No module named _curses;Color support is disabled, python-curses is not installed.解决办法

    linux系统默认安装了python2.6, 但是发现python2.7 import curses时 提示 找不到_curses 错误.  用pip(python2.7 )安装了curses-204 ...

  4. 更改Tomcat命令行窗体标题

     在windows下启动多个tomcat时.不好区分哪个tomcat相应哪个服务,能够通过下面方法设置Tomcat命令行窗体的标题: 1.在%tomcat_home%\bin\catalina.b ...

  5. cocos2d-x 3.0 final 移植 android

    准备工作 你仅仅要依照上一篇的 cocos2d-x 3.0 final 环境搭建 完毕就能够了 1.编辑proj.android\jni\Android.mk,更改内容例如以下 LOCAL_PATH ...

  6. Codeforces 424 C. Magic Formulas

    xor是满足交换律的,展开后发现仅仅要能高速求出 [1mod1....1modn],....,[nmod1...nmodn]的矩阵的xor即可了....然后找个规律 C. Magic Formulas ...

  7. POJ - 3233 Matrix Power Series (矩阵等比二分求和)

    Description Given a n × n matrix A and a positive integer k, find the sum S = A + A2 + A3 + - + Ak. ...

  8. EF使用自定义字符串连接数据库

    edmx的构造函数: public TestCheckUpdatesEntities(): base(Config.DataBaseConnectionString(), "TestChec ...

  9. iGrimaceVX3.0和1.44在线源手机直接安装教程

    [第一步] 先安装好三个组件设备必须是苹果越狱好后 确定6点几跟7点几的版本号才干够 首先打开cydia 选开发人员 以下 点软件源 点右上角编辑  1加入源 apt.25pp.com和IG包下载源a ...

  10. Spring官方文档翻译——15.1 介绍Spring Web MVC框架

    Part V. The Web 文档的这一部分介绍了Spring框架对展现层的支持(尤其是基于web的展现层) Spring拥有自己的web框架--Spring Web MVC.在前两章中会有介绍. ...