魔改——MFC SDI程序 转换为 MDI程序
==================================声明==================================
本文原创,转载在正文中显要的注明作者和出处,并保证文章的完整性。
未经作者同意请勿修改(包括本声明),保留法律追究的权利。
未经作者同意请勿用于出版、印刷或学术引用。
本文不定期修正完善,为保证内容正确,建议移步原文处阅读。
本文链接:http://www.cnblogs.com/wlsandwho/p/4286906.html
=======================================================================
之前有个程序,写的时候用的SDI然后分割视图左侧创建Outlook工具栏右侧不同视图。现在打算改成MDI。毕竟使用Ribbon的MDI还是很好看的。
=======================================================================
网上找了找资料,好多都是VC6时代的,不是很好。所以自己写一个留着,万一以后忘了呢?!
基于VS2010,MFC,未打SP1。
=======================================================================
先创建一个SDI,待会把它修改为MDI。




=======================================================================
下面创建一个MDI,作为参照。




=======================================================================
有一个事情一定要记住,既然要改,肯定是要把所有S的改成M的!所以,最后不放心可以用查找再找一遍。
魔改开始!
=======================================================================
看TestSDISample工程的InitInstance函数。
// CTestSDISampleApp 初始化 BOOL CTestSDISampleApp::InitInstance()
{
// 如果一个运行在 Windows XP 上的应用程序清单指定要
// 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,
//则需要 InitCommonControlsEx()。否则,将无法创建窗口。
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(FALSE); // 使用 RichEdit 控件需要 AfxInitRichEdit2()
// AfxInitRichEdit2(); // 标准初始化
// 如果未使用这些功能并希望减小
// 最终可执行文件的大小,则应移除下列
// 不需要的特定初始化例程
// 更改用于存储设置的注册表项
// TODO: 应适当修改该字符串,
// 例如修改为公司或组织名
SetRegistryKey(_T("应用程序向导生成的本地应用程序"));
LoadStdProfileSettings(); // 加载标准 INI 文件选项(包括 MRU) InitContextMenuManager(); InitKeyboardManager(); InitTooltipManager();
CMFCToolTipInfo ttParams;
ttParams.m_bVislManagerTheme = TRUE;
theApp.GetTooltipManager()->SetTooltipParams(AFX_TOOLTIP_TYPE_ALL,
RUNTIME_CLASS(CMFCToolTipCtrl), &ttParams); // 注册应用程序的文档模板。文档模板
// 将用作文档、框架窗口和视图之间的连接
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CTestSDISampleDoc),
RUNTIME_CLASS(CMainFrame), // 主 SDI 框架窗口
RUNTIME_CLASS(CTestSDISampleView));
if (!pDocTemplate)
return FALSE;
AddDocTemplate(pDocTemplate); // 分析标准 shell 命令、DDE、打开文件操作的命令行
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo); // 调度在命令行中指定的命令。如果
// 用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序,则返回 FALSE。
if (!ProcessShellCommand(cmdInfo))
return FALSE; // 唯一的一个窗口已初始化,因此显示它并对其进行更新
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
// 仅当具有后缀时才调用 DragAcceptFiles
// 在 SDI 应用程序中,这应在 ProcessShellCommand 之后发生
return TRUE;
}
再对照TestMDIReference的InitInstance函数。
// CTestMDIReferenceApp 初始化 BOOL CTestMDIReferenceApp::InitInstance()
{
// 如果一个运行在 Windows XP 上的应用程序清单指定要
// 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,
//则需要 InitCommonControlsEx()。否则,将无法创建窗口。
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(); // 使用 RichEdit 控件需要 AfxInitRichEdit2()
// AfxInitRichEdit2(); // 标准初始化
// 如果未使用这些功能并希望减小
// 最终可执行文件的大小,则应移除下列
// 不需要的特定初始化例程
// 更改用于存储设置的注册表项
// TODO: 应适当修改该字符串,
// 例如修改为公司或组织名
SetRegistryKey(_T("应用程序向导生成的本地应用程序"));
LoadStdProfileSettings(); // 加载标准 INI 文件选项(包括 MRU) InitContextMenuManager(); InitKeyboardManager(); InitTooltipManager();
CMFCToolTipInfo ttParams;
ttParams.m_bVislManagerTheme = TRUE;
theApp.GetTooltipManager()->SetTooltipParams(AFX_TOOLTIP_TYPE_ALL,
RUNTIME_CLASS(CMFCToolTipCtrl), &ttParams); // 注册应用程序的文档模板。文档模板
// 将用作文档、框架窗口和视图之间的连接
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(IDR_TestMDIReferencTYPE,
RUNTIME_CLASS(CTestMDIReferenceDoc),
RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架
RUNTIME_CLASS(CTestMDIReferenceView));
if (!pDocTemplate)
return FALSE;
AddDocTemplate(pDocTemplate); // 创建主 MDI 框架窗口
CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame || !pMainFrame->LoadFrame(IDR_MAINFRAME))
{
delete pMainFrame;
return FALSE;
}
m_pMainWnd = pMainFrame;
// 仅当具有后缀时才调用 DragAcceptFiles
// 在 MDI 应用程序中,这应在设置 m_pMainWnd 之后立即发生 // 分析标准 shell 命令、DDE、打开文件操作的命令行
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo); // 调度在命令行中指定的命令。如果
// 用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序,则返回 FALSE。
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// 主窗口已初始化,因此显示它并对其进行更新
pMainFrame->ShowWindow(m_nCmdShow);
pMainFrame->UpdateWindow(); return TRUE;
}
现在我们动手,先把
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CTestSDISampleDoc),
RUNTIME_CLASS(CMainFrame), // 主 SDI 框架窗口
RUNTIME_CLASS(CTestSDISampleView));
if (!pDocTemplate)
return FALSE;
AddDocTemplate(pDocTemplate);
中的CSingleDocTemplate改成CMultiDocTemplate,CMainFrame改成CChildFrame。顺便复制粘贴创建主框架窗口的代码。
理论性的东西看MFC的相关书籍吧,我就记着
CMainFrame=>CChildFrame=>(Template=Document + View),
而我们new的时候,在结构上可以理解为一下子做了后两部分,当然,实际上不是啊,好复杂的讲不了……
// 注册应用程序的文档模板。文档模板
// 将用作文档、框架窗口和视图之间的连接
// CSingleDocTemplate* pDocTemplate;
// pDocTemplate = new CSingleDocTemplate(
// IDR_MAINFRAME,
// RUNTIME_CLASS(CTestSDISampleDoc),
// RUNTIME_CLASS(CMainFrame), // 主 SDI 框架窗口
// RUNTIME_CLASS(CTestSDISampleView));
// if (!pDocTemplate)
// return FALSE;
// AddDocTemplate(pDocTemplate);
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CTestSDISampleDoc),
RUNTIME_CLASS(/*CMainFrame*/CChildFrame), // 主 SDI 框架窗口
RUNTIME_CLASS(CTestSDISampleView));
if (!pDocTemplate)
return FALSE;
AddDocTemplate(pDocTemplate);
// 创建主 MDI 框架窗口
CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame || !pMainFrame->LoadFrame(IDR_MAINFRAME))
{
delete pMainFrame;
return FALSE;
}
m_pMainWnd = pMainFrame;
// 仅当具有后缀时才调用 DragAcceptFiles
// 在 MDI 应用程序中,这应在设置 m_pMainWnd 之后立即发生
F7,看输出。
>------ 已启动生成: 项目: TestSDISample, 配置: Debug Win32 ------
>生成启动时间为 // ::。
>InitializeBuildStatus:
> 正在对“Debug\TestSDISample.unsuccessfulbuild”执行 Touch 任务。
>ClCompile:
> 所有输出均为最新。
> TestSDISample.cpp
>c:\wlscodehome\testsdisample\testsdisample\testsdisample.cpp(): error C2653: “CChildFrame”: 不是类或命名空间名称
>c:\wlscodehome\testsdisample\testsdisample\testsdisample.cpp(): error C2248: “CMainFrame::CMainFrame”: 无法访问 protected 成员(在“CMainFrame”类中声明)
> c:\wlscodehome\testsdisample\testsdisample\mainfrm.h() : 参见“CMainFrame::CMainFrame”的声明
> c:\wlscodehome\testsdisample\testsdisample\mainfrm.h() : 参见“CMainFrame”的声明
>
>生成失败。
>
>已用时间 ::00.15
========== 生成: 成功 个,失败 个,最新 个,跳过 个 ==========
第一个好处理,工程里没有的,就从MDI里复制粘贴一份,加进工程里就是了。(就不截图了。)
修改复制来的ChildFrm.cpp文件
#include "stdafx.h"
//#include "TestMDIReference.h"
#include "TestSDISample.h"
第二个,无法访问protected成员,就改成public的。
//protected: // 仅从序列化创建
public:
另外,参照MDI工程CMainFrame的声明,将基类修改为CMDIFrameWndEx,既然基类修改了,那么CMainFrame中就不能够再出现CFrameWndEx,所以省事的方法就是全部查找替换。
F7,无错误警告,运行。

点击新建

发先多视图是有了,但不是华丽好看的Tab页。
将MDI里CMainFrame::OnCreate中代码复制到SDI里CMainFrame::OnCreate相应的位置。
CMDITabInfo mdiTabParams;
mdiTabParams.m_style = CMFCTabCtrl::STYLE_3D_ONENOTE; // 其他可用样式...
mdiTabParams.m_bActiveTabCloseButton = TRUE; // 设置为 FALSE 会将关闭按钮放置在选项卡区域的右侧
mdiTabParams.m_bTabIcons = FALSE; // 设置为 TRUE 将在 MDI 选项卡上启用文档图标
mdiTabParams.m_bAutoColor = TRUE; // 设置为 FALSE 将禁用 MDI 选项卡的自动着色
mdiTabParams.m_bDocumentMenu = TRUE; // 在选项卡区域的右边缘启用文档菜单
EnableMDITabbedGroups(TRUE, mdiTabParams);
复制到
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (/*CFrameWndEx*/CMDIFrameWndEx::OnCreate(lpCreateStruct) == -)
return -; BOOL bNameValid;
// 基于持久值设置视觉管理器和样式
OnApplicationLook(theApp.m_nAppLook); CMDITabInfo mdiTabParams;
mdiTabParams.m_style = CMFCTabCtrl::STYLE_3D_ONENOTE; // 其他可用样式...
mdiTabParams.m_bActiveTabCloseButton = TRUE; // 设置为 FALSE 会将关闭按钮放置在选项卡区域的右侧
mdiTabParams.m_bTabIcons = FALSE; // 设置为 TRUE 将在 MDI 选项卡上启用文档图标
mdiTabParams.m_bAutoColor = TRUE; // 设置为 FALSE 将禁用 MDI 选项卡的自动着色
mdiTabParams.m_bDocumentMenu = TRUE; // 在选项卡区域的右边缘启用文档菜单
EnableMDITabbedGroups(TRUE, mdiTabParams); m_wndRibbonBar.Create(this);
m_wndRibbonBar.LoadFromResource(IDR_RIBBON); if (!m_wndStatusBar.Create(this))
{
TRACE0("未能创建状态栏\n");
return -; // 未能创建
} CString strTitlePane1;
CString strTitlePane2;
bNameValid = strTitlePane1.LoadString(IDS_STATUS_PANE1);
ASSERT(bNameValid);
bNameValid = strTitlePane2.LoadString(IDS_STATUS_PANE2);
ASSERT(bNameValid);
m_wndStatusBar.AddElement(new CMFCRibbonStatusBarPane(ID_STATUSBAR_PANE1, strTitlePane1, TRUE), strTitlePane1);
m_wndStatusBar.AddExtendedElement(new CMFCRibbonStatusBarPane(ID_STATUSBAR_PANE2, strTitlePane2, TRUE), strTitlePane2); // 启用 Visual Studio 2005 样式停靠窗口行为
CDockingManager::SetDockingMode(DT_SMART);
// 启用 Visual Studio 2005 样式停靠窗口自动隐藏行为
EnableAutoHidePanes(CBRS_ALIGN_ANY); return ;
}
F7,成功。

点击新建

=======================================================================
PS:
1 选项卡的标题在
pDocTemplate = new CMultiDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CTestSDISampleDoc),
RUNTIME_CLASS(/*CMainFrame*/CChildFrame), // 主 SDI 框架窗口
RUNTIME_CLASS(CTestSDISampleView));
的参数1中设置。
详见上一篇博文,标题很长的那个。
2 尚未搞清楚下面的代码(MDI的CMainFrame::OnCreate中的最后),所以没有添加。
// 启用增强的窗口管理对话框
EnableWindowsDialog(ID_WINDOW_MANAGER, ID_WINDOW_MANAGER, TRUE); // 将文档名和应用程序名称在窗口标题栏上的顺序进行交换。这
// 将改进任务栏的可用性,因为显示的文档名带有缩略图。
ModifyStyle(, FWS_PREFIXTITLE);
魔改——MFC SDI程序 转换为 MDI程序的更多相关文章
- 魔改——MFC SDI 支持 内嵌 EXCEL OLE
==================================声明================================== 本文版权归作者所有 未经作者授权 请勿转载 保留法律追究的 ...
- 魔改——MFC MDI程序 定制 文档模板 运行时全部打开 禁用关闭按钮
==================================声明================================== 本文原创,转载在正文中显要的注明作者和出处,并保证文章的完 ...
- VC++ MFC单文档应用程序SDI下调用glGenBuffersARB(1, &pbo)方法编译通过但执行时出错原因分析及解决办法:glewInit()初始化的错误
1.问题症状 在VC++环境下,利用MFC单文档应用程序SDI下开发OpenGL程序,当调用glGenBuffersARB(1, &pbo)方法编译通过但执行时出错,出错代码如下: OpenG ...
- MFC通过ODBC连接Mysql程序
分享到 一键分享 QQ空间 新浪微博 百度云收藏 人人网 腾讯微博 百度相册 开心网 腾讯朋友 百度贴吧 豆瓣网 搜狐微博 百度新首页 QQ好友 和讯微博 更多... 百度分享 MFC通过ODBC连接 ...
- 魔改——MDI多视图模板Tab/标签页 初始化/操作控件
==================================声明================================== 本文原创,转载在正文中显要的注明作者和出处,并保证文章的完 ...
- JAVA应用程序转换为Applet
本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/41673295 将一个图形的JAVA应用程序转换为能够嵌入在 ...
- windows mfc 程序,不同程序通信和互斥
1. 共享内存(项目中使用过) 我转备份文章:http://www.cnblogs.com/swing07/p/8087686.html CreateFileMapping 或 OpenFileMap ...
- MFC学习(三)程序入口和执行流程
1) WIN32 API程序当中,程序入口为WinMain函数,在这个函数当中我们完成注册窗口类,创建窗口,进入消息循环,最后由操作系统根据发送到程序窗口的消息调用程序窗口函数.而在MFC程序当中我们 ...
- [转帖]reptyr, 将正在运行的程序转换为新终端
reptyr, 将正在运行的程序转换为新终端 https://www.helplib.com/GitHub/article_45241 学习一下. 很抑郁的是 没有 arm64和龙芯平台的二进制文件. ...
随机推荐
- ASP.NET高并发解决方案
一.页面静态化: 二.运用WCF,WEB SERVICE等技术实现分布式业务逻辑处理及数据访问的能力: 三.页面缓存: 四.数据缓存: 五.建立图片文件服务器:
- CentOS6.5菜鸟之旅:安装SUN JDK1.7和Tomcat7
一.前言 CentOS6.5系统自带Open JDK1.7.1.6和1.5,但OpenJDK部分内容与SUN JDK不兼容,因此打算重新安装SUN JDK1.7来开发. 二.卸载Open JDK ...
- JS 对象属性相关--检查属性、枚举属性等
1.删除属性 delete运算符可以删除对象的属性 delete person.age //即person不再有属性age delete person['age'] //或者这样 delete只是断开 ...
- C#多态--虚方法实现多态
1.虚方法提供一种默认实现,子类可以选择是否重写,如果不重写,那么就使用父类已经实现的方法.(重写可以改变方法的指针) 如果需要改变类型指针,那么需要做方法的重写: 1.如果子类方法是重写方法,那么系 ...
- jQuery点缩略图显示大图片
2015年繁忙的一月份,无更多时间去学习ASP.NET MVC程序,二月份又是中国的新年,长达半个月的假期,望回到老家中,在无电脑无网络的日子里,能有更多时间陪伴年迈的父母亲. 今天学习jQuery的 ...
- 基于DevExpress开发的GridView如何实现一列显示不同的控件类型
在很多DevExpress的使用例子里面,我们可以看到,基于GridView实现的不同控件展示的时候,每一列的控件类型都是一样的,如果我要某一列的一行让用户可以从下列列表选择选项,而其他行不可选择,那 ...
- sql server2008中左连接,右连接,等值连接的区别
数据库中的连接我了解到有left join,right join,inner join这些,以下是它们的区别: 1)左连接(left join):先取出a表的所有数据,再取出a.b表相匹配的数据 2) ...
- C# on Visual Studio Code
installation Download .NET Core SDK installer and install it. https://www.microsoft.com/net/download ...
- WinJs项目介绍
WinJs库是最近微软公布的一个开源项目.它与开源社区的协作共同完成.为了轻易创建HTML/JS/CSS应用程序开发的解决方案.WinJS是一个Javascripts的工具箱让开发人员使用HT ...
- Oauth笔记
上周的工作有安全验证这一块,但不懂,只知道有几个关键字Oauth.secret-key .token.签名等.今天就查下资料做笔记. Oauth是什么 不依靠用户账号和密码就能获得访问资源权限 本质: ...