大家好,我是你的MFC编程"解谜师"!上次咱们聊了MFC的视图类超市,今天回归核心:文档与视图的"铁杆CP"结构。这玩意儿是MFC的灵魂 -- 文档管数据(仓库),视图管显示(橱窗),让你的程序逻辑清晰不乱套。今天用更接地气的语言重讲一遍,加点专业术语、幽默比喻(比如文档像"数据银行",视图像"ATM机"),再配上MDI项目初始化代码解析。读完这篇,你就知道MFC怎么"组队"运行,开发时少走弯路啦!
(PS: 本文基于MFC文档/视图基础,适合新手中级。结合VS2010创建MDITest项目实践,效果拔群。别忘了,上节的视图类就是这个结构的"皮肤"!)
文档与视图的"亲密关系":一对多,超级灵活
简单说,文档和视图是"一对多"映射:一个文档可对应多个视图 ,但一个视图只认一个文档。比喻:文档像个HTML文件(数据本体),视图像打开方式 -- 用记事本(纯文本视图)看是代码,用浏览器(富媒体视图)看是网页。俩视图都访问同一数据,但呈现不同!
为什么这样设计?优势大放送:
- 数据与显示分离:文档专管存储/管理数据(结构化保存),视图专管呈现/交互(多种方式秀数据)。比如一份报表:表格视图(列表式)、图表视图(饼图式) -- 数据不变,换个"皮肤"而已。
- 开发福利:你专注数据逻辑,不用纠结UI。MFC帮你隔离了"后台仓库"和"前台橱窗"。
有趣比喻:文档是"富豪"(有数据金矿),视图是"代言人"(多张脸宣传)。一个富豪可雇多个代言人,但每个代言人只为一个老板打工!
整体结构:不止文档+视图,还有"媒婆"和"老板"
开发MFC应用时,别光盯文档/视图 -- 实际涉及4大金刚:
- 文档模板(CDocTemplate):像"媒婆",撮合文档、视图和框架。
- 文档(CDocument):数据仓库。
- 视图(CView):数据橱窗。
- 框架窗口(CFrameWnd):大老板,管界面整体(如菜单、工具栏)。
下面用VC2010创建的多文档(MDI)项目MDITest为例,拆解初始化过程。代码来自CWinApp的InitInstance() -- 这就是程序"出生"时刻!
初始化过程:从"种子"到"开花"全解析
MFC启动像搭乐高:先建框架,再组文档/视图。看看MDITest的InitInstance代码(我加了注释,方便理解):
cpp
BOOL CMDITestApp::InitInstance() {
// 初始化公共控件(Windows XP可视化)
INITCOMMONCONTROLSEX InitCtrls;
InitCtrls.dwSize = sizeof(InitCtrls);
InitCtrls.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&InitCtrls);
CWinAppEx::InitInstance(); // 基类初始化
// 初始化OLE库(对象链接嵌入)
if (!AfxOleInit()) {
AfxMessageBox(IDP_OLE_INIT_FAILED);
return FALSE;
}
AfxEnableControlContainer(); // 启用控件容器
EnableTaskbarInteraction(); // 任务栏交互
// 其他初始化:注册表、MRU(最近文件)、菜单/键盘/提示管理...
SetRegistryKey(_T("本地应用程序")); // 存设置的注册表键
LoadStdProfileSettings(4); // 加载INI选项,包括最近文件
InitContextMenuManager();
InitKeyboardManager();
InitTooltipManager();
// 提示样式设置(可选)
// 关键:创建多文档模板(媒婆登场!)
CMultiDocTemplate* pDocTemplate = new CMultiDocTemplate(
IDR_MDITestTYPE, // 资源ID
RUNTIME_CLASS(CMDITestDoc), // 文档类
RUNTIME_CLASS(CChildFrame), // MDI子框架
RUNTIME_CLASS(CMDITestView)); // 视图类
if (!pDocTemplate) return FALSE;
AddDocTemplate(pDocTemplate); // 添加到模板管理器
// 创建主框架窗口(老板上位)
CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame || !pMainFrame->LoadFrame(IDR_MAINFRAME)) {
delete pMainFrame;
return FALSE;
}
m_pMainWnd = pMainFrame; // 设置主窗口
// 处理命令行(打开文件等)
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
if (!ProcessShellCommand(cmdInfo)) return FALSE;
// 显示并更新主窗口
pMainFrame->ShowWindow(m_nCmdShow);
pMainFrame->UpdateWindow();
return TRUE;
}
流程拆解(通俗版):
- 前戏准备:初始化控件、OLE、注册表等(像铺床热身)。
- 创建模板:用CMultiDocTemplate(多文档版)或CSingleDocTemplate(单文档版),指定文档、框架、视图类。AddDocTemplate()把它加到管理器 -- 这步把三者"绑"一起!
- 建主框架:new CMainFrame,加载资源(菜单等),设为m_pMainWnd。
- 处理命令:解析命令行(如打开文件)。
- 开张:显示窗口,程序跑起来!
幽默比喻:初始化像办婚礼 -- 模板是媒婆(撮合三人),框架是婚礼会場(管现场),最后ShowWindow是"开席"!
文档模板的"魔法":如何关联三人组?
文档模板(CDocTemplate基类)是幕后英雄,能关联框架、文档、视图。因为它内部存了三者的CRuntimeClass指针(运行时类信息) -- 在构造函数里初始化!单文档用CSingleDocTemplate(一对一),多文档用CMultiDocTemplate(多开)。
专业小知识:这种设计超巧妙 -- 通过运行时类型信息(RTTI),MFC动态创建实例。学习时,多debug模板构造函数,体会"媒婆"的智慧。
文档类:数据"仓库管理员"
文档派生自CDocument,负责存/管数据,并分享给别人。源码里看CDocument定义 -- 它有序列化(Serialize)等功能。
关键:文档维护一个CPtrList m_viewList(视图链表) -- 用**AddView()**加视图,**RemoveView()**删视图。一个文档可有多个"粉丝"视图!
比喻:文档像银行金库,视图是ATM -- 金库管钱,ATM取钱。
小经验:MFC类多如牛毛,新手别怕 -- 多动手!比如在代码里调用AddView,加个视图跑跑看效果。调试查看m_viewList,理解链表维护。
视图类:数据"互动橱窗"
CView是所有视图的基类,主要两大活:
- 呈现数据:从文档取数据,画到屏幕。
- 接受修改:用户输入(鼠标/键盘),反馈给文档。
视图里有CDocument* m_pDocument 指针 -- 用GetDocument()取文档。修改数据后,别忘调用文档的UpdateAllViews() -- 通知所有关联视图刷新(像群发微信更新)!
比喻:视图像超市橱窗 -- 秀商品(数据),顾客戳戳(输入),橱窗反馈给仓库(文档)。
框架窗口:界面"大老板"
框架(CFrameWnd基类)管整体UI:菜单、工具栏、状态栏。分两种:
- SDI(单文档):最多一个框架,像独栋别墅。
- MDI(多文档):主框架下多个子框架(CMDIChildWnd),像公寓大楼 -- 可同时开多个文档/视图。
MDI里,主框架是"总部",子框架是"分店"。
结语:掌握结构,MFC开发如鱼得水
文档/视图结构是MFC的杀手锏 -- 分离数据与UI,让你高效 coding。初始化懂了,模板的关联get了,文档/视图的互动熟了,下步就实践吧!赶紧建个MDITest项目,改改InitInstance,加个视图试试UpdateAllViews。
有问题?评论区开喷!点赞收藏转发,一起征服MFC~
(本文CSDN原创,基于MFC文档/视图知识。欢迎交流,转载请注明出处。编程如搭积木,结构稳了才高楼!)