QT,C#可在代码中关联事件和事件函数,且关联可取,极其方便。反观VC,只能用宏关联,且需程序一开始就关联消息和消息函数,运行中不可取消关联。MFC如此包装很不优雅。在用代码创建控件和菜单,或想用一个消息函数处理多个消息时,我更愿意在代码中作消息映射。VC虽已老朽,但仍有不少公司在用,且还有旧VC项目需维护,因此有必要在此分享“如何用代码实现消息映射”。
MFC的消息机制,有的博主写得非常详细,这里就不赘述。简单说MFC是利用宏(BEGIN_MESSAGE_MAP,END_MESSAGE_MAP等)将消息和消息函数的关联放在一个数组中,但这个数组是static const类型,无法对数组内容作改动,因此就无法在代码中向该数组添加消息映射。
如需手动关联,我的做法是,取消消息映射宏,自行消息映射宏向代码中添加的函数,并自定义一个数组,用于保存消息映射,步骤如下:
1.在头文件中声明一个静态数组
static std::vector< AFX_MSGMAP_ENTRY> _messageEntries;
2.在实现文件中定义这个静态数组
std::vector< AFX_MSGMAP_ENTRY> CDialog_MsgTest::_messageEntries;
3.将实现文件中那段宏BEGIN_MESSAGE_MAP,END_MESSAGE_MAP删除
4.实现GetMessageMap函数
const AFX_MSGMAP* CDialog_MsgTest::GetMessageMap() const
{
return GetThisMessageMap();
}
5.实现GetThisMessageMap函数
const AFX_MSGMAP* PASCAL CDialog_MsgTest::GetThisMessageMap()
{
typedef CDialog TheBaseClass;
if(_messageEntries.size() == 0)
{
AFX_MSGMAP_ENTRY entry = {1, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } ;
_messageEntries.insert(_messageEntries.begin(),entry);
};
static AFX_MSGMAP messageMap;
messageMap.pfnGetBaseMap = &TheBaseClass::GetThisMessageMap;
messageMap.lpEntries = &_messageEntries[0];
return &messageMap;
}
6.添加你的消息处理函数,以按钮点击为例
头文件中加入afx_msg void OnBnClickedButton1();
并在实现文件实现该函数
7.实现消息映射
AFX_MSGMAP_ENTRY entry = { nMessage, nCode, nID, nLastID, nSig, pfn};
_messageEntries.insert(_messageEntries.begin(),entry);
entry中各值如何填,需要参考MFC的消息映射宏的定义,比如ON_COMMAND的定义如下:
#define ON_COMMAND(id, memberFxn) \
{ WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)id, AfxSigCmd_v, \
static_cast<AFX_PMSG> (memberFxn) },
则代码实现消息映射应如下填,以按钮点击为例,
AFX_MSGMAP_ENTRY entry = { WM_COMMAND, (WORD)BN_CLICKED, (WORD)IDC_BUTTON1, (WORD)IDC_BUTTON1, AfxSigCmd_v,(static_cast< AFX_PMSG > (&CDialog_MsgTest::OnBnClickedButton1)};
_messageEntries.insert(_messageEntries.begin(),entry);
8.取消消息映射
以上述entry中的各值为条件,在_messageEntries中找到该映射并作移除即可
作者邮箱:zztolll@163.com