
CChildFrame做为子窗口包含于MDIClient中(可以包含多个),CChildFrame里面则是真实的文档表示窗口CMDITestView了。 我们从这里开始:// CMDITestApp 初始化BOOL CMDITestApp::InitInstance() 做为CWinApp的派生类,通常需要重载InitInstance(), ExitInstance()两个函数,以完成应用的初始化和退出。我们现在关心InitInstance中关于文档模板、窗口处理的部分,而忽略掉一些CommonControl, OLE初始化部分。 整个InitInstance代码如下:BOOL CMDITestApp::InitInstance(){ InitCommonControls(); // 这里删减了大量注释和错误处理 CWinApp::InitInstance(); AfxOleInit(); AfxEnableControlContainer(); SetRegistryKey(_T(“应用程序向导生成的本地应用程序“)); LoadStdProfileSettings(4); // 加载标准 INI 文件选项(包括 MRU) TRACE(“Before CMultiDocTemplate\n“); // 注册应用程序的文档模板。文档模板 // 将用作文档、框架窗口和视图之间的连接 CMultiDocTemplate pDocTemplate; pDocTemplate = new CMultiDocTemplate(IDR_MDITestTYPE, RUNTIME_CLASS(CMDITestDoc), RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架 RUNTIME_CLASS(CMDITestView)); if (!pDocTemplate) return FALSE; TRACE(“Before AddDocTemplate\n“); AddDocTemplate(pDocTemplate); // 创建主 MDI 框架窗口 TRACE(“Before new CMainFrame\n“); CMainFrame pMainFrame = new CMainFrame; TRACE(“Before pMainFrame->LoadFrame\n“); if (!pMainFrame || !pMainFrame->LoadFrame(IDR_MAINFRAME)) return FALSE; m_pMainWnd = pMainFrame; TRACE(“Before ParseCommandLine\n“); CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); // 调度在命令行中指定的命令。如果 // 用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序,则返回 FALSE。 TRACE(“Before ProcessShellCommand\n“); if (!ProcessShellCommand(cmdInfo)) return FALSE; TRACE(“Before pMainFrame->ShowWindow\n“); // 主窗口已初始化,因此显示它并对其进行更新 pMainFrame->ShowWindow(m_nCmdShow); TRACE(“Before pMainFrame->UpdateWindow\n“); pMainFrame->UpdateWindow(); return TRUE;} 为了研究整个创建过程,我在其中添加了一些TRACE来跟踪创建顺序。 忽略掉开始的乱七八糟的初始化,从CMultiDocTemplate开始: CMultiDocTemplate pDocTemplate = new CMultiDocTemplate(IDR_MDITestTYPE, RUNTIME_CLASS(CMDITestDoc), RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架 RUNTIME_CLASS(CMDITestView)); AddDocTemplate(pDocTemplate);(作了一点点简化)这里首先创建了一个CMultiDocTemplate ——文档模板,文档模板包括的三个运行时刻类信息:Document – CMDITestDoc, FrameWnd – CChildFrame, View – CMDITestView。然后通AddDocTemplate函数将新创建的文档模板添加到模板管理器之中(我们以后再研究模板管理器)。 然后创建主框架窗口CMainFrame: CMainFrame pMainFrame = new CMainFrame; if (!pMainFrame || !pMainFrame->LoadFrame(IDR_MAINFRAME)) return FALSE; 其中,需要研究的是LoadFrame的实现,以及里面都做了些什么。我们稍后研究。 处理命令行,在这里第一个空文档被建立出来: CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); // 调度在命令行中指定的命令。如果用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序,则返回 FALSE。 if (!ProcessShellCommand(cmdInfo)) // �0�8 这里创建出初始空文档 return FALSE; 我们一会会重点研究ProcessShellCommand。 最后,显示主窗口: pMainFrame->ShowWindow(m_nCmdShow); pMainFrame->UpdateWindow(); 至此,WinApp::InitInstance()完成了自己的工作。 上面遗留了三个待研究的分支,让我们现在去研究它们:1、 CDocTemplate2、 CFrameWnd::LoadFrame3、 CWnd::ProcessShellCommand 研究CDocTemplate 我们的例子中是构造了一个CMultiDocTemplate,它是从CDocTemplate派生而来,所以我们主要研究CDocTemplate。CDocTemplate的几个关键属性列表如下: CRuntimeClass m_pDocClass; // class for creating new documents CRuntimeClass m_pFrameClass; // class for creating new frames CRuntimeClass m_pViewClass; // class for creating new views 其中:m_pDocClass表示文档类类型,在此例子中就是CMDITestDocm_pFrameClass表示容纳View窗口的框架窗口类类型,此例中为CChildFramem_pViewClass表示显示文档的View视类类型,此例中为CMDITestView 我们可以这样认为,CDocTemplate用于描述Frame-View-Doc的关系。当然它还有一大堆别的属性,我们暂时先忽略。 一会还会看到CDocTemplate的创建文档、框架、视的过程,<在ProcessShellCommand中研究。 研究LoadFrame 让我们继续研究CFrameWnd::LoadFrame是怎么运作的。使用的方法是跟踪进入。。。BOOL CMDIFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd pParentWnd, CCreateContext pContext){ // 调用基类 CFrameWnd 的 LoadFrame, pContext 在创建主窗口时 = NULL // pParentWnd = NULL if (!CFrameWnd::LoadFrame(nIDResource, dwDefaultStyle, pParentWnd, pContext)) return FALSE; // save menu to use when no active MDI child window is present ASSERT(m_hWnd != NULL); // 主窗口带有菜单,所以。。。 m_hMenuDefault = ::GetMenu(m_hWnd); if (m_hMenuDefault == NULL) TRACE(traceAppMsg, 0, “Warning: CMDIFrameWnd without a default menu\n“); return TRUE;}注意,我们的MDITest Application的主窗口CMainFrame是从CMDIFrameWnd派生的,所以进入到这里,参考代码中红色的注释部分。继续跟踪进入CFrameWnd::LoadFrame。 BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd pParentWnd, CCreateContext pContext){ // only do this once ASSERT_VALID_IDR(nIDResource); // nIDResource = 128, IDR_MAINFRAME ASSERT(m_nIDHelp == 0 || m_nIDHelp == nIDResource); m_nIDHelp = nIDResource; // ID for help context (+HID_BASE_RESOURCE) CString strFullString; if (strFullStringLoadString(nIDResource)) // = “MDITest” AfxExtractSubString(m_strTitle, strFullString, 0); // 取得第一个子串 VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG)); // attempt to create the window // GetIconWndClass 会调用 virtual PreCreateWindow 函数,别处也会调用,从而 // 使得子类的PreCreateWindow 将被调用多次 LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource); CString strTitle = m_strTitle; // 调用 CFrameWnd::Create() 实际创建出窗口。 // 注意:在这里将给 CMainFrame 发送 WM_CREATE 等多个消息。触发 CMainFrame 的 // OnCreate 处理等。 if (!Create(lpszClass, strTitle, dwDefaultStyle, rectDefault, pParentWnd, MAKEINTRESOURCE(nIDResource), 0L, pContext)) { return FALSE; // will self destruct on failure normally } // save the default menu handle, 好像CMDIFrameWnd 也保存了一次? ASSERT(m_hWnd != NULL); m_hMenuDefault = ::GetMenu(m_hWnd); // load accelerator resource LoadAccelTable(MAKEINTRESOURCE(nIDResource)); // WM_INITIALUPDATE 是 MFC 发明的消息,参见后面的说明。 if (pContext == NULL) // send initial update SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE); return TRUE;} 以下是从TN024: MFC-Defined Messages And Resources中抽取的部分说明:WM_INITIALUPDATEThis message is sent by the document template to all descendants of a frame window when it is safe for them to do their initial update It maps to a call to CView::OnInitialUpdate but can be used in other CWnd-derived classes for other one-shot updatingwParamNot used (0)lParamNot used (0)returnsNot used (0) 归纳一下,LoadFrame中进行了如下事情:1、 注册窗口类(AfxDeferRegisterClass)2、 实际创建窗口(Create)3、 处理菜单、快捷键,发送WM_INITIALUPDATE消息给所有子窗口。实际将在CView中处理此消息。(例如:在ToolBar上面放一个FormView,可能就能收到这个消息并处利?) 至此,CMainFrame已经成功创建,菜单已经装载,工具条、状态行等已经在CMainFrame::OnCreate中创建。让我们接着研究第一个子窗口是怎么被创建出来的,该过程和CMainFrame::LoadFrame比起来就不那么直接了。 研究CWnd::ProcessShellCommand 第一个MDI子窗口是从这里面建立出来的,这实在是缺乏直观性。不过MFC就是这样,没办法。BOOL CWinApp::ProcessShellCommand(CCommandLineInfo& rCmdInfo){ BOOL bResult = TRUE; switch (rCmdInfom_nShellCommand) { case CCommandLineInfo::FileNew: if (!AfxGetApp()->OnCmdMsg(ID_FILE_NEW, 0, NULL, NULL)) // 关键是这里 OnFileNew(); if (m_pMainWnd == NULL) bResult = FALSE; break; case CCommandLineInfo::FileOpen: // 忽略 case CCommandLineInfo::FilePrintTo: // 忽略 case CCommandLineInfo::FilePrint: case CCommandLineInfo::FileDDE: case CCommandLineInfo::AppRegister: case CCommandLineInfo::AppUnregister: } return bResult;}进入到ProcessShellCommand,要处理很多种不同命令,我们忽略其它命令,单独看FileNew部分。注意:实际进入到了AfxGetApp()->OnCmdMsg(ID_FILE_NEW, 0, NULL, NULL)之中。 AfxGetApp()实际返回了CMDITestApp的唯一实例,它从CWinApp – CWinThread – CCmdTarget – CObject 派生而来。我们没有重载OnCmdMsg,所以进入到CCmdTarget的OnCmdMsg处理中。为了研究,我们删减了一些代码。BOOL CCmdTarget::OnCmdMsg(UINT nID, int nCode, void pExtra, AFX_CMDHANDLERINFO pHandlerInfo){ // 这里删减了一些代码 // determine the message number and code (packed into nCode) const AFX_MSGMAP pMessageMap; const AFX_MSGMAP_ENTRY lpEntry; UINT nMsg = 0; // 这里删减了一些代码,处理后 nMsg = WM_COMMAND // 为了简化,删减了一些断言等。以下循环用于查找处理此消息的入口。
>_<!!,
文件-新建-工程-MFC AppWizard(exe),输入工程名称,点确定;
开始是多重文档,选择第三个选项(基于对话框),后面如果不想改变,直接点完成即可。
选择重新编译就可以了。
这个问题和微软的预编译策略有关,所以每个工程都有个stdafxh,具体可以参考有关资料。
控制台要使用MFC库,首先include头文件,如afxwinh等,然后大多数情况下需要自己定义宏,#define _AFXDLL表示动态连接MFC库。
TRACE属于MFC,所以以上的 *** 作都不能少,否则程序通不过编译。
--------------------------
使用MFC的方法不是说了么!
楼主没尝试过我的方法么?
1)
在stdafxh的末尾添加:
#define _AFXDLL
#include <afxwinh>
#include <afxexth>
2)重新编译
-----------------------------
试过了,还是不行。是怎么个不行呢?是程序编译通不过呢还是编译成功,但你不会看TRACE输出?
-----------------------------
看到楼主这样的代码了--“#include <iostream>using namespace std;”
楼主是不是以为TRACE是把信息输出到控制台的?TRACE是把信息输出到调试器的“输出”窗口的,要看信息,是要到“输出”窗口看的。
创建MFC窗口程序
添加菜单栏 :对应 : 文件 -- 选项 -- 查看
添加TabCtrl控件分页: 应用程序 -- 进程 -- 服务
每个分页单独插入一个Dialog对话框,Style属性设为Child,在代码中移动子页到TabCtrl的子页上
进程,服务什么的,是一个ListCtrl列表控件,控件属性设置View:设置为Report
方法/步骤
要WIN8或是WIN7上打开VS2010软件,文件-新建-项目 如下图所示,选择MFC应用程序
选择自己适合的路径,并给此项目命名,选择下一步,按如下所示配置属性,注意要选 应用程序类型-基于对话框属性,然后下一步
用户界面功能,在此界面下一般默认设置,下一步
高级功能,默认,下一步
生成类-选后缀是dlg结尾的类,前面是你的工程名,我的工程名是CMFCApplication1所以在此处是CMFCApplication1Dlg,下一步
完成后如下所示,MFC向导建成,相关类已封装好,是不是可以做点你想的事了?当然
链接-编译生成EXE可执行文件,如下所示
然后运行ctrl+f5,利用你所学习的MFC知识开始你的学习吧!下面是我做的一个简单的显示。
望采纳
以上就是关于学习MFC框架如何创建的过程全部的内容,包括:学习MFC框架如何创建的过程、如何用VC++6.0创建MFC对话框应用程序、VC2005 怎么创建一个空的MFC应用程序等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)