==================================声明==================================

本文原创,转载在正文中显要的注明作者和出处,并保证文章的完整性。

未经作者同意请勿修改(包括本声明),保留法律追究的权利。

未经作者同意请勿用于出版、印刷或学术引用。

本文不定期修正完善,为保证内容正确,建议移步原文处阅读。

本文链接: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);

最新文章

  1. Oracle位图索引
  2. [LeetCode] Remove Duplicate Letters 移除重复字母
  3. (转载)Win8.1的版本
  4. PHP的学习--可变变量
  5. MySQL mac 安装
  6. MC java 远程调试 plugin 开发
  7. HDU 1023 Traning Problem (2) 高精度卡特兰数
  8. Event Logging
  9. iCheck表单美化插件使用方法详解(含参数、事件等)
  10. 使用pscp实现Windows 和 Linux服务器间远程拷贝文件
  11. stagefright框架(三)-选择Video Decode
  12. iOS参考工具和资源
  13. 在Linux上创建Postgresql数据库
  14. 理解js中的运算符优先级
  15. 移动 云MAS 发短信 .net HTTP 请求
  16. java web石家庄铁道大学课程管理系统
  17. 搭建Keil C51开发环境
  18. Removing Timezone from XMLGregorianCalendar
  19. hdu 5013 优化疑问+dp
  20. 深挖android low memory killer

热门文章

  1. IOS开发UI基础UIImageView属性属性
  2. Scrum 3.2 多鱼点餐系统开发进度(页面优化&下单详细信息页面)
  3. 关于Form.Close跟Form.Dispose
  4. Python基础:映射(字典)
  5. IDEA默认常用快捷键
  6. 重新想象 Windows 8 Store Apps (48) - 多线程之其他辅助类: SpinWait, SpinLock, Volatile, SynchronizationContext, CoreDispatcher, ThreadLocal, ThreadStaticAttribute
  7. 与众不同 windows phone (51) - 8.1 新增控件: DatePickerFlyout, TimePickerFlyout
  8. java之AbstractStringBuilder类详解
  9. JMS学习(一)基本概念
  10. Java文件编码自动转换工具类(只改变编码,不会改变文件内容)