《VC++深入详解》第三章


这一章开始进入MFC的世界了,以一个Wizard生成的单文档类型工程为例,将MFC程序的基本框架进行了剖析,让我们看到了WIN32的影子。

新建立的单文档类型工程Test,包括如下几个类(继承关系也一并列出):

CTestApp----从CWinApp---CWinThread---CCmdTarget---Cobject继承而来,代表应用本身

CAboutDlg----CDialog---CWnd---CCmdTarget---Cobject,帮助对话框

CMainFrame----CFrameWnd---CWnd---CCmdTarget---Cobject 框架类,主窗口(窗口、菜单、工具栏、状态栏)

CTestView---CView---CWnd---CCmdTarget---Cobject 视类,用于数据的显示,外部输入的响应

CTestDoc---CDocument---CCmdTarget---Cobject 数据,在MFC里Document就是数据的意思,MVC的思想是将数据本身与数据的显示分离开来,CView用于数据的显示。CFrameWnd\CView\CDocument组成了文档三人组,在多文档应用里,每打开一个文档即会创建一个三人组。


在工程里,我们没法直接找到WinMain的身影,这是因为这部分对于所有APP都是一样的,FrameWork当然代劳之,在连接阶段将完成WinMain的加入。下面是该MFC程序的生死流程:

在工程里,我们发现有一个很重要的全局变量CTestApp theApp,全局变量的构造必然在main函数执行之前,在其基类CWinApp的构造函数里有如下这句:

CWinApp::CWinApp()

{

......

AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();

pModuleState->m_pCurrentWinApp = this;

}

这里便将我们定义的对象CTestApp交给了FrameWork了。

在WinMain中我们会看到如下代码(为了便于理解,稍做了修改)

int AFXAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLint, int nCmdShow)

{

......

CWinApp *pApp = AfxGetApp(); //Get the point of theApp object

pApp->InitInstance(); //InitInstance is virtual func, so

return(pApp->Run());

}

注意到虚函数InitInstance,我们之前WIN32程序里的一系列动作(设计窗口类、注册、创建窗口、显示、更新、消息循环)都蕴含其中。

在InitInstance中有如下关键代码:

BOOL CTestApp::InitInstance()
{
<span style="white-space:pre">	</span>......
	// Register the application's document templates.  Document templates
	//  serve as the connection between documents, frame windows and views.

	CSingleDocTemplate* pDocTemplate;
	pDocTemplate = new CSingleDocTemplate(
		IDR_MAINFRAME,
		RUNTIME_CLASS(CTestDoc),
		RUNTIME_CLASS(CMainFrame),       // main SDI frame window
		RUNTIME_CLASS(CTestView));
	AddDocTemplate(pDocTemplate);


	// The one and only window has been initialized, so show and update it.
	m_pMainWnd->ShowWindow(SW_SHOW);
	m_pMainWnd->UpdateWindow();

	return TRUE;
}

这里使用了MFC的“动态创建”技术来创建三人组对象,并使用CSingleDocTemple管理三者。有了窗口类对象才有窗口一说,切勿本末倒置。接下来进入“设计、注册窗口类以及创建窗口”的环节,在第一章WIN32编程里,我们不是还需要指定窗口类名称么,这里怎么没有传递该信息进去?对于单文档类型这种已知的窗口类型,MFC当然知道。

m_pMainWnd指向的是主窗口对象,View窗口是其子窗口。

pApp->Run其实就是我们的消息循环了。

若我们未对主窗口、视类窗口的窗口过程函数进行修改,那么MFC会调用其默认的。但实际情况,我们程序员的主要职责便是改写窗口过程函数。

至此,这便是一个MFC程序的典型框架。

接下来看一些细枝末节的东西:

(1)在CTestApp中响应来自菜单ID_APP_ABOUT的命令消息,所有继承自CCmdTarget的类均可以响应命令消息。

(2)在CTestDoc中有一个Serialize的虚函数,该函数用于文档的“读写”,这里的读写是针对对象级的,读取时可以使用MFC的动态创建技术实现对象的恢复。


本章的最后举了一个在主窗口、视类窗口显示一个按钮的例子,用于说明主窗口的工作区以及主窗口、视类窗口之间的关系。CButton m_btn是谁的成员不重要,重要的是调用其Create时,使用的父窗口是谁。

int CTestView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CView::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	// TODO: Add your specialized creation code here

	m_btn.Create("按钮",WS_CHILD | BS_DEFPUSHBUTTON,CRect(0,0,100,100),GetParent(),123);
//	m_btn.Create("按钮",WS_CHILD | BS_DEFPUSHBUTTON,CRect(0,0,100,100),this,123);
	m_btn.ShowWindow(SW_SHOWNORMAL);
	
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值