第六章 MFC程序的生死因果
MFC学习过程,这个方法不错,条例清晰。
1、CWinApp -- 取代WinMain地位
WinMain函数的功能由CWinApp的三个函数实现
1 virtual BOOL InitApplication(); 2 virtual BOOL InitInstance(); 3 virtual int Run();
在CWinThread类中定义m_pMainWnd
CWnd* m_pMainWnd; // 记录主窗口的句柄
2、CFrameWnd --- 取代WndProc的地位
通过消息映射来实现消息与函数的关联,宏DECLARE_MESSAGE_MAP()
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
ON_WM_PAINT()
ON_COMMAND(IDM_ABOUT, OnAbout)
END_MESSAGE_MAP()
3、运行过程
1 Ctest7App theApp;//全局对象
2 AfxWinInit(...) 在头文件afxwin.h中定义的AfxWinInit(....),这个函数的参数和WndProc()的一样。
1 BOOL AFXAPI AfxWinInit( HINSTANCE hInstance, HINSTANCE hPrevInstance, //在CWind中被引用为友元函数 2 LPTSTR lpCmdLine, int nCmdShow);
//在这个函数中 的主要动作之一 CWinApp* pApp = AfxGetApp();//导致CWinApp::InitApplication()的调用
// 之二 AfxInitThread();//初始化线程
3 CWinApp::InitApplication(); //初始化应用
4 BOOL Ctest7App::InitInstance();//自己定义的类
注意:
应用程序一定要改写虚拟函数InitInstance,因为它在CWinApp 中只是个空函数,没有任何内建(预设)动作。
5 CFrameWnd::Create()产生窗口(并先注册窗口类别)
1 BOOL Create( LPCTSTR lpszClassName,//窗口类别 2 LPCTSTR lpszWindowName,//窗口标题 3 DWORD dwStyle = WS_OVERLAPPEDWINDOW,//窗口样式 4 const RECT& rect = rectDefault,//窗口位置和大小 5 CWnd* pParentWnd = NULL,//父窗口 6 LPCTSTR lpszMenuName = NULL,//指定菜单 7 DWORD dwExStyle = 0,//附加样式 8 CCreateContext* pContext = NULL );//在文档/视图中会用到,这里为默认值NULL
在Create()中调用PreCreateWindow();//虚函数
然后在PreCreateWindow()中调用宏AfxDeferRegisterClass();
6 窗口的更新与显示
m_pMainWnd->ShowWindow(m_nCmdShow);//显示窗口
m_pMainWnd->UpdateWindow();//发送WM_PAINT消息
7 CWinApp::Run() ---- 程序的活水源头
Run()内部有一个GetMessage/DispatchMesage 循环
函数接收到WM_PAINT消息,通过消息映射跳转到OnPaint()函数
整个运行机制看起来很复杂,但是只要多看几遍,必然能熟记于心中,为以后的程序书写打下基础。总结如下:
程序的诞生:
Application object 产生,内存于是获得配置,初值亦设立了。
Afx WinMain 执行AfxWinInit,后者又调用AfxInitThread,把消息队列尽量加大到96。
Afx WinMain 执行InitApplication。这是CWinApp 的虚拟函数,但我们通常不改写它。
AfxWinMain 执行InitInstance。这是CWinApp 的虚拟函数,我们必须改写它。
CMyWinApp::InitInstance 'new' 了一个CMyFrameWnd 对象。
CMyFrameWnd 构造式调用Create,产生主窗口。我们在Create 参数中指定的窗口类别是NULL, 于是MFC 根据窗口种类, 自行为我们注册一个名为"AfxFrameOrView42d" 的窗口类别。
回到InitInstance 中继续执行ShowWindow,显示窗口。
执行UpdateWindow,于是发出WM_PAINT。
回到AfxWinMain,执行Run,进入消息循环。
程序开始运作:
程序获得WM_PAINT 消息(藉由CWinApp::Run 中的::GetMessage 循环)。
WM_PAINT 经由::DispatchMessage 送到窗口函数CWnd::DefWindowProc 中。
CWnd::DefWindowProc 将消息绕行过消息映射表格(Message Map)。
绕行过程中发现有吻合项目,于是调用项目中对应的函数。此函数是应用程序利用BEGIN_MESSAGE_MAP 和END_MESSAGE_MAP 之间的宏设立起来的。
标准消息的处理例程亦有标准命名,例如WM_PAINT 必然由OnPaint 处理。程序的死亡:
使用者选按【File/Close】,于是发出WM_CLOSE。
CMyFrameWnd 并没有设置WM_CLOSE 处理例程,于是交给预设之处理例程。
预设函数对于WM_CLOSE 的处理方式是调用::DestroyWindow, 并因而发出WM_DESTROY。
预设之WM_DESTROY 处理方式是调用::PostQuitMessage,因此发出WM_QUIT。
CWinApp::Run 收到WM_QUIT 后会结束其内部之消息循环, 然后调用ExitInstance,这是CWinApp 的一个虚拟函数。
如果CMyWinApp 改写了ExitInstance , 那么CWinApp::Run 所调用的就是CMyWinApp::ExitInstance,否则就是CWinApp::ExitInstance。
最后回到AfxWinMain,执行AfxWinTerm,结束程序。
4、Callback函数-----全局函数 或者 static 函数
定义:凡是由你设计而却由Windows 系统调用的函数,统称为callback 函数。这些函数都有一定的类型,以配合Windows的调用动作。
注意:如果类别的成员函数是一个callback 函数, 你必须声明它为"static",才能把C++ 编译器加诸于函数的一个隐藏参数this 去掉。
5、 空闲时间(idle time)的处理:OnIdle
如果你的MFC 程序也想处理idle time,只要改写CWinApp 衍生类别的OnIdle 函数即可 virtual BOOL OnIdle(LONG lCount);
6、Dialog 与 Control
MFC中的对话框的创建与打开使用CDialog类。下面是一些常用的对话框:
类别 类型 CCommonDialog 以下各类别的父类别 CFileDialog File 对话框(Open 或Save As) CPrintDialog Print 对话框 CFindReplaceDialog Find and Replace 对话框 CColorDialog Color 对话框 CFontDialog Font 对话框 CPageSetupDialog Page Setup 对话框(MFC 4.0 新增) COleDialog Ole 相关对话框
派生关系如图:
具体使用方法参考MSDN