MFC程序各个文件
在上一篇《从Win32过渡到MFC工程》中,我们将所有的逻辑写在了一个cpp文件中,现在我们对文件进行整理。
FirstMFC的功能:弹出一个窗口,显示窗口对应的图标、窗口名、窗口可以相应各种事件。
FirstMFC头文件与CPP文件分开
FirstMFC.h进行声明
class CMyApp :public CWinApp { public: BOOL InitInstance(); };
FirstMFC.cpp实现头文件的相关声明
引入公用的头文件(stdafx.h)和同名的头文件、MainDlg.h(对话框)
stdafx.h内容(公共资源)如下:
#include <afxwin.h> #include "resource.h"
资源的添加方式是通过源文件->添加资源的引导界面实现的:
此处的CMainDlg对话框和图标IDI_LOGO都是通过此方式添加的。
实现同名头文件声明的函数
#include "stdafx.h" #include "FirstMFC.h" #include "MainDlg.h" BOOL CMyApp::InitInstance() { CMainDlg dlg; dlg.DoModal(); return TRUE; } CMyApp theApp;
MainDlg.h头文件主要内容如下:
1、CMainDlg的一些声明信息(声明函数定义、资源ID定义包括对话框资源,图标资源等);
2、DECLARE_MESSAGE_MAP() 宏定义,声明消息映射,一般这个宏调用写在类定义的结尾处;
3、对应消息处理函数的声明。
class CMainDlg :public CDialog { private: enum{ IDD = IDD_MAIN_DLG }; public: HICON m_hIcon; HICON m_hIcon1; CMainDlg(); BOOL OnInitDialog(); //声明消息映射 DECLARE_MESSAGE_MAP() public: afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); //WM_CREATE消息处理函数 afx_msg void OnClose(); //WM_CLOSE消息处理函数 };
在对内容3中的消息处理函数声明的时候,有的时候消息处理函数签名我们不能时刻记住,可以通过类向导来实现。通过类向导界面操作,可以在对应头文件中声明消息处理函数、同时在对应cpp文件中书写好消息处理函数的实现。
步骤如下:切换到类视图,在对应的CMainDlg类上进行类向导操作。右键->类向导->点击添加处理程序
即可看到MainDlg头文件和CPP文件下添加如下代码:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); //MainDlg.h中
//cpp中 int CMainDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CDialog::OnCreate(lpCreateStruct) == -1) return -1; // TODO: 在此添加您专用的创建代码 return 0; }
同时在MainDlg.cpp中的BEGIN_MESSAGE_MAP(CMainDlg, CDialog)和END_MESSAGE_MAP之间增加对应名称的消息映射。
在BEGIN_MESSAG_MAP和END_MESSAGE_MAP之间的内容成为消息映射入口项。
//消息映射 BEGIN_MESSAGE_MAP(CMainDlg, CDialog)//开始消息映射 ON_WM_CREATE() END_MESSAGE_MAP()//结束消息映射
消息映射表
在类定义文件MainDlg.h中添加的宏DECLARE_MESSAGE_MAP()我们查看该宏,如下:
protected: static const AFX_MSGMAP* PASCAL GetThisMessageMap(); virtual const AFX_MSGMAP* GetMessageMap() const;
其声明了两个函数GetThisMessageMap和GetMessageMap。
在类的实现文件MainDlg.cpp中BEGIN_MESSAGE_MAP宏的信息如下:
#define BEGIN_MESSAGE_MAP(theClass, baseClass) PTM_WARNING_DISABLE const AFX_MSGMAP* theClass::GetMessageMap() const { return GetThisMessageMap(); } const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap() { typedef theClass ThisClass; typedef baseClass TheBaseClass; static const AFX_MSGMAP_ENTRY _messageEntries[] = { # define END_MESSAGE_MAP() {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } }; static const AFX_MSGMAP messageMap = { &TheBaseClass::GetThisMessageMap, &_messageEntries[0] }; return &messageMap; }
我们将theClass和baseClass分别替换为实际传入的CMainDlg和CDialog,替换END_MESSAGE_MAP宏,最后的结果如下:
const AFX_MSGMAP* CMainDlg::GetMessageMap() const { return GetThisMessageMap(); } const AFX_MSGMAP* PASCAL CMainDlg::GetThisMessageMap() { typedef CMainDlg ThisClass; typedef CDialog TheBaseClass; static const AFX_MSGMAP_ENTRY _messageEntries[] = { { WM_CREATE, 0, 0, 0, AfxSig_is, (AFX_PMSG)(AFX_PMSGW)(static_cast< int (AFX_MSG_CALL CWnd::*)(LPCREATESTRUCT) > (&ThisClass::OnCreate)) }, { WM_CLOSE, 0, 0, 0, AfxSig_vv, (AFX_PMSG)(AFX_PMSGW)(static_cast< void (AFX_MSG_CALL CWnd::*)(void) > (&ThisClass::OnClose)) }, { WM_DESTROY, 0, 0, 0, AfxSig_vv, (AFX_PMSG)(AFX_PMSGW)(static_cast< void (AFX_MSG_CALL CWnd::*)(void) > (&ThisClass::OnDestroy)) }, { WM_PAINT, 0, 0, 0, AfxSig_vv, (AFX_PMSG)(AFX_PMSGW)(static_cast< void (AFX_MSG_CALL CWnd::*)(void) > (&ThisClass::OnPaint)) }, { WM_LBUTTONDOWN, 0, 0, 0, AfxSig_vwp, (AFX_PMSG)(AFX_PMSGW)(static_cast< void (AFX_MSG_CALL CWnd::*)(UINT, CPoint) > (&ThisClass::OnLButtonDown)) }, { WM_LBUTTONUP, 0, 0, 0, AfxSig_vwp, (AFX_PMSG)(AFX_PMSGW)(static_cast< void (AFX_MSG_CALL CWnd::*)(UINT, CPoint) > (&ThisClass::OnLButtonUp)) }, { WM_LBUTTONDBLCLK, 0, 0, 0, AfxSig_vwp, (AFX_PMSG)(AFX_PMSGW)(static_cast< void (AFX_MSG_CALL CWnd::*)(UINT, CPoint) > (&ThisClass::OnLButtonDblClk)) }, { WM_MOUSEMOVE, 0, 0, 0, AfxSig_vwp, (AFX_PMSG)(AFX_PMSGW)(static_cast< void (AFX_MSG_CALL CWnd::*)(UINT, CPoint) > (&ThisClass::OnMouseMove)) }, { WM_TIMER, 0, 0, 0, AfxSig_v_up_v, (AFX_PMSG)(AFX_PMSGW)(static_cast< void (AFX_MSG_CALL CWnd::*)(UINT_PTR) > (&ThisClass::OnTimer)) }, { WM_SIZE, 0, 0, 0, AfxSig_vwii, (AFX_PMSG)(AFX_PMSGW)(static_cast< void (AFX_MSG_CALL CWnd::*)(UINT, int, int) > (&ThisClass::OnSize)) }, { UM_TEST, 0, 0, 0, AfxSig_lwl, (AFX_PMSG)(AFX_PMSGW)(static_cast< LRESULT(AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM)>(&CMainDlg::OnTest)) }, { WM_COMMAND, (WORD)BN_CLICKED, (WORD)IDC_BTN_TEST, (WORD)IDC_BTN_TEST, AfxSigCmd_v, (static_cast< AFX_PMSG > (&CMainDlg::OnBtnTest)) }, { 0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } }; static const AFX_MSGMAP messageMap = { &TheBaseClass::GetThisMessageMap, &_messageEntries[0] }; return &messageMap; }
其为类定义文件中的宏DECLARE_MESSAGE_MAP()声明的两个函数的实现。_messageEntries数组中每个AFX_MSGMAP_ENTRY对象元素对应了每个消息绑定的处理函数,且处理函数在
类定义文件中也已声明(以afx_msg开头)。这里我们完善了消息的种类,增加了WM开头的命令消息WM_COMMAND和自定义消息UM_TEST。
结构体AFX_MSGMAP_ENTRY信息如下:
struct AFX_MSGMAP_ENTRY { UINT nMessage; // windows message UINT nCode; // control code or WM_NOTIFY code UINT nID; // control ID (or 0 for windows messages) UINT nLastID; // used for entries specifying a range of control id's UINT_PTR nSig; // signature type (action) or pointer to message # AFX_PMSG pfn; // routine to call (or special value) };