开始我们先不多说,先看几张图,根据图我们来做进一步剖析。
在main或WinMain之前,全局变量已经被分配内存并初始化了。
1. 在MFC中在WinMain之前有个theApp全局变量先被构造并被初始化,而由于子类构造函数执行前,其父类的构造函数先被执行,所以CTestApp的父类CWinAPP的构造函数先执行。产生了theApp对象后,在WinMain()中的指针*pThread和*pApp就有了内容。
CWinAPP中,有一句:
pModuleState->m_pCurrentWinApp= this;
this代表的是子类的对象,就是theApp。
MFC大致流程:
CTestApp theApp;//构造全局对象
中间调用其构造函数CTestApp()
其父类的构造函数要先执行:CWinApp().
WinMain()
{
AfxWinMain();//调用下面的函数
}
AfxWinMain()
{
//获取这两个类型的指针,对CTestApp来说,他们指向的都是CTestApp类的对象,也就是theApp
CWinThread*pThread = AfxGetThread();
CWinAppp *pApp =AfxGetApp();
//完成MFC内部管理方面的工作
pApp->InitApplication();
pThread->Initinstance();//初始化工作和注册窗口类,窗口显示和更新
pThread->Run();//消息循环
}
而在BOOL CTestApp::InitInstance()中的代码
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CTestDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CTestView));
AddDocTemplate(pDocTemplate);
完成了将这三个类关联起来的工作。
下面我们 就要来设计窗口类,但是MFC已经给我们预定义了一些标准窗口,下面就来注册窗口类:
AfxEndDeferRegisterClass函数完成。
要先判断窗口类性,然后赋予其相应的类名字。
之后调用AfxRegisterClass来注册窗口类。
他首先获得窗口类信息,看一下是否已经注册。
还有一个窗口时程序框架窗口:CMainFrame, 这个类有PreCreateWindow函数,在窗口产生之前被调用。
调用前要先调用CFrameWnd的PreCreateWindow函数。
这里也是在theApp全局对象和WinMain函数之后到达这里,在WinMain之后来进行窗口的注册和产生。
创建窗口:
由CWnd类的CreateEx函数实现。
CFrameWnd的Create函数内部也是调用了这个CreateEx函数。
显示和更新窗口:
程序中中一个m_pMainWnd成员,这是一个CWnd类型指针,保存了应用程序框架对象的指针,也就是指向CMainFrame对象的指针。
在CTestApp中,InitInstance函数有代码:
BOOL CTheappApp::InitInstance() { AfxEnableControlContainer(); // Standard initialization // If you are not using these features and wish to reduce the size // of your final executable, you should remove from the following // the specific initialization routines you do not need. #ifdef _AFXDLL Enable3dControls(); // Call this when using MFC in a shared DLL #else Enable3dControlsStatic(); // Call this when linking to MFC statically #endif // Change the registry key under which our settings are stored. // TODO: You should modify this string to be something appropriate // such as the name of your company or organization. SetRegistryKey(_T("Local AppWizard-Generated Applications")); LoadStdProfileSettings(); // Load standard INI file options (including MRU) // 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(CTheappDoc), RUNTIME_CLASS(CMainFrame), // main SDI frame window RUNTIME_CLASS(CTheappView)); AddDocTemplate(pDocTemplate); // Parse command line for standard shell commands, DDE, file open CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); // Dispatch commands specified on the command line if (!ProcessShellCommand(cmdInfo)) return FALSE; // The one and only window has been initialized, so show and update it. m_pMainWnd->ShowWindow(SW_SHOW); m_pMainWnd->UpdateWindow(); return TRUE; }
里面有:
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
这两句代码来显示和更新窗口。
消息循环:
CWinThread的 Run函数完成消息循环这一任务。
pThread->Run();
在Run中有一个函数叫做:PumpMessage函数,这个函数里面有GetMessage,TranslateMessage,DispatchMessage函数。完成消息循环。
在我们这册窗口类的时候AfxEndDeferRegisterClass函数,里面有一句:wndcls.lpfnWndProc= DefWindowProc;
在MFC中,我们采用一种叫做消息映射的机制来处理各种消息。
消息映射:
1、 消息响应函数原型
在类中,有
//{{AFX_MSG(****)
afx_msg void *****();
//}}AFX_MSG
函数其中AFX_MSG是注释宏。 这个宏说明这个函数是一个消息响应函数声明。
2、 消息:ON_WM_LBUTTONDOWN消息映射宏
BEGIN_MESSAGE_MAP(**,**)
//{{AFX_MSG_MAP(**)
ON_WM_LBUTONDOWN()
//}}AFX_MSG_MAP
ON_COMMAND(ID, 函数)
END_MESSAGE_MAP()
两个宏之间定义了类的消息映射表,其中ON_WM_LBUTTONDOWN是消息映射宏。
3、 消息响应函数定义
声明了函数我们就可以来定义函数了。
MFC的消息映射机制的具体实现方法:在每个能接收和处理消息的类中,定义一个消息和消息函数静态对照表,即消息映射表,在消息映射表中,消息与对应的消息处理函数指针是成对出现的,某个类能处理的所有消息及其对应的消息处理函数的地址都列在这个类多对应的静态表中。当有消息需要处理时,程序只要搜索消息静态表,查看表中是否含有该消息,就可以知道该类能否处理此消息,如果能就童谣依照静态表能很容易找到并调用对应的消息处理函数。
4.如何在单文档文件中显示一个CButton的对象?
在CMainFrame::OnCreate()中定义一个CButton的对象btn;然后调用btn.Create("维新",WS_DISABLED |WS_CHILD | WS_VISIBLE| BS_AUTO3STATE,
CRect(0,0,300,100),/*GetParent(),*/this,123);
注意点:
(1).此处btn不能是局部变量,否则它的生命周期太短,将不能显示。
(2).在create函数的第二个参数中加入WS_VISIBLE 参数才行。否则必须调用ShowWindow
也可以在view的OnCreate消息响应函数中加入
(3).CButton类的定义头文件在afxwin.h中,而stdafx.h包含了afxwin.h,所以可以直接使用。因为MFC中的每一个类中都有#include "stdafx.h"的声明。
C++中,窗口类对象与窗口并不是一回事,他们之间唯一的关系是c++窗口类对象内部定义了一个窗口句柄变量,保存了与这个c++窗口类对象相关的那个窗口的句柄,销毁窗口的时候,与之对应的c++窗口类对象销毁与否,要看其生命周期是否结束,但是c++窗口类对象销毁时,与之相关的窗口也将销毁。
2012/10/28
jofranks 于南昌