码迷,mamicode.com
首页 > 编程语言 > 详细

魔改——MFC SDI转MDI

时间:2015-02-11 23:17:55      阅读:366      评论:0      收藏:0      [点我收藏+]

标签:

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

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

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

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

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

本文链接:http://www.cnblogs.com/wlsandwho/p/4286906.html

=======================================================================

之前有个程序,写的时候用的SDI然后分割视图左侧创建Outlook工具栏右侧不同视图。现在打算改成MDI。毕竟使用Ribbon的MDI还是很好看的。

=======================================================================

网上找了找资料,好多都是VC6时代的,不是很好。所以自己写一个留着,万一以后忘了呢?!

基于VS2010,MFC,未打SP1。

=======================================================================

先创建一个SDI,待会把它修改为MDI。

技术分享

技术分享

技术分享

技术分享

=======================================================================

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

 技术分享

技术分享

技术分享

技术分享

=======================================================================

有一个事情一定要记住,既然要改,肯定是要把所有S的改成M的!所以,最后不放心可以用查找再找一边。

魔改开始!

=======================================================================

TestSDISample工程的InitInstance函数。

 1 // CTestSDISampleApp 初始化
 2 
 3 BOOL CTestSDISampleApp::InitInstance()
 4 {
 5     // 如果一个运行在 Windows XP 上的应用程序清单指定要
 6     // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,
 7     //则需要 InitCommonControlsEx()。否则,将无法创建窗口。
 8     INITCOMMONCONTROLSEX InitCtrls;
 9     InitCtrls.dwSize = sizeof(InitCtrls);
10     // 将它设置为包括所有要在应用程序中使用的
11     // 公共控件类。
12     InitCtrls.dwICC = ICC_WIN95_CLASSES;
13     InitCommonControlsEx(&InitCtrls);
14 
15     CWinAppEx::InitInstance();
16 
17 
18     // 初始化 OLE 库
19     if (!AfxOleInit())
20     {
21         AfxMessageBox(IDP_OLE_INIT_FAILED);
22         return FALSE;
23     }
24 
25     AfxEnableControlContainer();
26 
27     EnableTaskbarInteraction(FALSE);
28 
29     // 使用 RichEdit 控件需要  AfxInitRichEdit2()    
30     // AfxInitRichEdit2();
31 
32     // 标准初始化
33     // 如果未使用这些功能并希望减小
34     // 最终可执行文件的大小,则应移除下列
35     // 不需要的特定初始化例程
36     // 更改用于存储设置的注册表项
37     // TODO: 应适当修改该字符串,
38     // 例如修改为公司或组织名
39     SetRegistryKey(_T("应用程序向导生成的本地应用程序"));
40     LoadStdProfileSettings(0);  // 加载标准 INI 文件选项(包括 MRU)
41 
42 
43     InitContextMenuManager();
44 
45     InitKeyboardManager();
46 
47     InitTooltipManager();
48     CMFCToolTipInfo ttParams;
49     ttParams.m_bVislManagerTheme = TRUE;
50     theApp.GetTooltipManager()->SetTooltipParams(AFX_TOOLTIP_TYPE_ALL,
51         RUNTIME_CLASS(CMFCToolTipCtrl), &ttParams);
52 
53     // 注册应用程序的文档模板。文档模板
54     // 将用作文档、框架窗口和视图之间的连接
55     CSingleDocTemplate* pDocTemplate;
56     pDocTemplate = new CSingleDocTemplate(
57         IDR_MAINFRAME,
58         RUNTIME_CLASS(CTestSDISampleDoc),
59         RUNTIME_CLASS(CMainFrame),       // 主 SDI 框架窗口
60         RUNTIME_CLASS(CTestSDISampleView));
61     if (!pDocTemplate)
62         return FALSE;
63     AddDocTemplate(pDocTemplate);
64 
65 
66     // 分析标准 shell 命令、DDE、打开文件操作的命令行
67     CCommandLineInfo cmdInfo;
68     ParseCommandLine(cmdInfo);
69 
70 
71 
72     // 调度在命令行中指定的命令。如果
73     // 用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序,则返回 FALSE。
74     if (!ProcessShellCommand(cmdInfo))
75         return FALSE;
76 
77     // 唯一的一个窗口已初始化,因此显示它并对其进行更新
78     m_pMainWnd->ShowWindow(SW_SHOW);
79     m_pMainWnd->UpdateWindow();
80     // 仅当具有后缀时才调用 DragAcceptFiles
81     //  在 SDI 应用程序中,这应在 ProcessShellCommand 之后发生
82     return TRUE;
83 }

再对照TestMDIReference的InitInstance函数。

 1 // CTestMDIReferenceApp 初始化
 2 
 3 BOOL CTestMDIReferenceApp::InitInstance()
 4 {
 5     // 如果一个运行在 Windows XP 上的应用程序清单指定要
 6     // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,
 7     //则需要 InitCommonControlsEx()。否则,将无法创建窗口。
 8     INITCOMMONCONTROLSEX InitCtrls;
 9     InitCtrls.dwSize = sizeof(InitCtrls);
10     // 将它设置为包括所有要在应用程序中使用的
11     // 公共控件类。
12     InitCtrls.dwICC = ICC_WIN95_CLASSES;
13     InitCommonControlsEx(&InitCtrls);
14 
15     CWinAppEx::InitInstance();
16 
17 
18     // 初始化 OLE 库
19     if (!AfxOleInit())
20     {
21         AfxMessageBox(IDP_OLE_INIT_FAILED);
22         return FALSE;
23     }
24 
25     AfxEnableControlContainer();
26 
27     EnableTaskbarInteraction();
28 
29     // 使用 RichEdit 控件需要  AfxInitRichEdit2()    
30     // AfxInitRichEdit2();
31 
32     // 标准初始化
33     // 如果未使用这些功能并希望减小
34     // 最终可执行文件的大小,则应移除下列
35     // 不需要的特定初始化例程
36     // 更改用于存储设置的注册表项
37     // TODO: 应适当修改该字符串,
38     // 例如修改为公司或组织名
39     SetRegistryKey(_T("应用程序向导生成的本地应用程序"));
40     LoadStdProfileSettings(0);  // 加载标准 INI 文件选项(包括 MRU)
41 
42 
43     InitContextMenuManager();
44 
45     InitKeyboardManager();
46 
47     InitTooltipManager();
48     CMFCToolTipInfo ttParams;
49     ttParams.m_bVislManagerTheme = TRUE;
50     theApp.GetTooltipManager()->SetTooltipParams(AFX_TOOLTIP_TYPE_ALL,
51         RUNTIME_CLASS(CMFCToolTipCtrl), &ttParams);
52 
53     // 注册应用程序的文档模板。文档模板
54     // 将用作文档、框架窗口和视图之间的连接
55     CMultiDocTemplate* pDocTemplate;
56     pDocTemplate = new CMultiDocTemplate(IDR_TestMDIReferencTYPE,
57         RUNTIME_CLASS(CTestMDIReferenceDoc),
58         RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架
59         RUNTIME_CLASS(CTestMDIReferenceView));
60     if (!pDocTemplate)
61         return FALSE;
62     AddDocTemplate(pDocTemplate);
63 
64     // 创建主 MDI 框架窗口
65     CMainFrame* pMainFrame = new CMainFrame;
66     if (!pMainFrame || !pMainFrame->LoadFrame(IDR_MAINFRAME))
67     {
68         delete pMainFrame;
69         return FALSE;
70     }
71     m_pMainWnd = pMainFrame;
72     // 仅当具有后缀时才调用 DragAcceptFiles
73     //  在 MDI 应用程序中,这应在设置 m_pMainWnd 之后立即发生
74 
75     // 分析标准 shell 命令、DDE、打开文件操作的命令行
76     CCommandLineInfo cmdInfo;
77     ParseCommandLine(cmdInfo);
78 
79 
80 
81     // 调度在命令行中指定的命令。如果
82     // 用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序,则返回 FALSE。
83     if (!ProcessShellCommand(cmdInfo))
84         return FALSE;
85     // 主窗口已初始化,因此显示它并对其进行更新
86     pMainFrame->ShowWindow(m_nCmdShow);
87     pMainFrame->UpdateWindow();
88 
89     return TRUE;
90 }

现在我们动手,先把

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的时候,在结构上可以理解为一下子做了后两部分,当然,实际上不是啊,好复杂的讲不了……

 1     // 注册应用程序的文档模板。文档模板
 2     // 将用作文档、框架窗口和视图之间的连接
 3 //     CSingleDocTemplate* pDocTemplate;
 4 //     pDocTemplate = new CSingleDocTemplate(
 5 //         IDR_MAINFRAME,
 6 //         RUNTIME_CLASS(CTestSDISampleDoc),
 7 //         RUNTIME_CLASS(CMainFrame),       // 主 SDI 框架窗口
 8 //         RUNTIME_CLASS(CTestSDISampleView));
 9 //     if (!pDocTemplate)
10 //         return FALSE;
11 //     AddDocTemplate(pDocTemplate);
12     CMultiDocTemplate* pDocTemplate;
13     pDocTemplate = new CMultiDocTemplate(
14         IDR_MAINFRAME,
15         RUNTIME_CLASS(CTestSDISampleDoc),
16         RUNTIME_CLASS(/*CMainFrame*/CChildFrame),       // 主 SDI 框架窗口
17         RUNTIME_CLASS(CTestSDISampleView));
18     if (!pDocTemplate)
19         return FALSE;
20     AddDocTemplate(pDocTemplate);
21     // 创建主 MDI 框架窗口
22     CMainFrame* pMainFrame = new CMainFrame;
23     if (!pMainFrame || !pMainFrame->LoadFrame(IDR_MAINFRAME))
24     {
25         delete pMainFrame;
26         return FALSE;
27     }
28     m_pMainWnd = pMainFrame;
29     // 仅当具有后缀时才调用 DragAcceptFiles
30     //  在 MDI 应用程序中,这应在设置 m_pMainWnd 之后立即发生

F7,看输出。

 1 1>------ 已启动生成: 项目: TestSDISample, 配置: Debug Win32 ------
 2 1>生成启动时间为 2015/2/11 21:24:22 3 1>InitializeBuildStatus:
 4 1>  正在对“Debug\TestSDISample.unsuccessfulbuild”执行 Touch 任务。
 5 1>ClCompile:
 6 1>  所有输出均为最新。
 7 1>  TestSDISample.cpp
 8 1>c:\wlscodehome\testsdisample\testsdisample\testsdisample.cpp(125): error C2653: “CChildFrame”: 不是类或命名空间名称
 9 1>c:\wlscodehome\testsdisample\testsdisample\testsdisample.cpp(131): error C2248: “CMainFrame::CMainFrame”: 无法访问 protected 成员(在“CMainFrame”类中声明)
10 1>          c:\wlscodehome\testsdisample\testsdisample\mainfrm.h(21) : 参见“CMainFrame::CMainFrame”的声明
11 1>          c:\wlscodehome\testsdisample\testsdisample\mainfrm.h(17) : 参见“CMainFrame”的声明
12 1>
13 1>生成失败。
14 1>
15 1>已用时间 00:00:00.15
16 ========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========

第一个好处理,工程里没有的,就从MDI里复制粘贴一份,加进工程里就是了。(就不截图了。)

修改复制来的ChildFrm.cpp文件

#include "stdafx.h"
//#include "TestMDIReference.h"
#include "TestSDISample.h"

第二个,无法访问protected成员,就改成public的。

1 //protected: // 仅从序列化创建
2 public:

另外,参照MDI工程CMainFrame的声明,将基类修改为CMDIFrameWndEx,既然基类修改了,那么CMainFrame中就不能够再出现CFrameWndEx,所以省事的方法就是全部查找替换。

F7,无错误警告,运行。

技术分享

点击新建

技术分享

发先多视图是有了,但不是华丽好看的Tab页。

将MDI里CMainFrame::OnCreate中代码复制到SDI里CMainFrame::OnCreate相应的位置。

1     CMDITabInfo mdiTabParams;
2     mdiTabParams.m_style = CMFCTabCtrl::STYLE_3D_ONENOTE; // 其他可用样式...
3     mdiTabParams.m_bActiveTabCloseButton = TRUE;      // 设置为 FALSE 会将关闭按钮放置在选项卡区域的右侧
4     mdiTabParams.m_bTabIcons = FALSE;    // 设置为 TRUE 将在 MDI 选项卡上启用文档图标
5     mdiTabParams.m_bAutoColor = TRUE;    // 设置为 FALSE 将禁用 MDI 选项卡的自动着色
6     mdiTabParams.m_bDocumentMenu = TRUE; // 在选项卡区域的右边缘启用文档菜单
7     EnableMDITabbedGroups(TRUE, mdiTabParams);

复制到

 1 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
 2 {
 3     if (/*CFrameWndEx*/CMDIFrameWndEx::OnCreate(lpCreateStruct) == -1)
 4         return -1;
 5 
 6     BOOL bNameValid;
 7     // 基于持久值设置视觉管理器和样式
 8     OnApplicationLook(theApp.m_nAppLook);
 9 
10     CMDITabInfo mdiTabParams;
11     mdiTabParams.m_style = CMFCTabCtrl::STYLE_3D_ONENOTE; // 其他可用样式...
12     mdiTabParams.m_bActiveTabCloseButton = TRUE;      // 设置为 FALSE 会将关闭按钮放置在选项卡区域的右侧
13     mdiTabParams.m_bTabIcons = FALSE;    // 设置为 TRUE 将在 MDI 选项卡上启用文档图标
14     mdiTabParams.m_bAutoColor = TRUE;    // 设置为 FALSE 将禁用 MDI 选项卡的自动着色
15     mdiTabParams.m_bDocumentMenu = TRUE; // 在选项卡区域的右边缘启用文档菜单
16     EnableMDITabbedGroups(TRUE, mdiTabParams);
17 
18     m_wndRibbonBar.Create(this);
19     m_wndRibbonBar.LoadFromResource(IDR_RIBBON);
20 
21     if (!m_wndStatusBar.Create(this))
22     {
23         TRACE0("未能创建状态栏\n");
24         return -1;      // 未能创建
25     }
26 
27     CString strTitlePane1;
28     CString strTitlePane2;
29     bNameValid = strTitlePane1.LoadString(IDS_STATUS_PANE1);
30     ASSERT(bNameValid);
31     bNameValid = strTitlePane2.LoadString(IDS_STATUS_PANE2);
32     ASSERT(bNameValid);
33     m_wndStatusBar.AddElement(new CMFCRibbonStatusBarPane(ID_STATUSBAR_PANE1, strTitlePane1, TRUE), strTitlePane1);
34     m_wndStatusBar.AddExtendedElement(new CMFCRibbonStatusBarPane(ID_STATUSBAR_PANE2, strTitlePane2, TRUE), strTitlePane2);
35 
36     // 启用 Visual Studio 2005 样式停靠窗口行为
37     CDockingManager::SetDockingMode(DT_SMART);
38     // 启用 Visual Studio 2005 样式停靠窗口自动隐藏行为
39     EnableAutoHidePanes(CBRS_ALIGN_ANY);
40 
41     return 0;
42 }

F7,成功。

技术分享

点击新建

技术分享

 

=======================================================================

PS:

1 选项卡的标题在

1     pDocTemplate = new CMultiDocTemplate(
2         IDR_MAINFRAME,
3         RUNTIME_CLASS(CTestSDISampleDoc),
4         RUNTIME_CLASS(/*CMainFrame*/CChildFrame),       // 主 SDI 框架窗口
5         RUNTIME_CLASS(CTestSDISampleView));

的参数1中设置。

详见上一篇博文,标题很长的那个

2 尚未搞清楚下面的代码(MDI的CMainFrame::OnCreate中的最后),所以没有添加。

1     // 启用增强的窗口管理对话框
2     EnableWindowsDialog(ID_WINDOW_MANAGER, ID_WINDOW_MANAGER, TRUE);
3 
4     // 将文档名和应用程序名称在窗口标题栏上的顺序进行交换。这
5     // 将改进任务栏的可用性,因为显示的文档名带有缩略图。
6     ModifyStyle(0, FWS_PREFIXTITLE);

 

魔改——MFC SDI转MDI

标签:

原文地址:http://www.cnblogs.com/wlsandwho/p/4286906.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!