马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
MFC 项目里给菜单栏加一项、点了弹出一个对话框,看着简单,实际要改两个文件、填三段代码,新手经常漏掉其中一步导致"菜单点了没反应"。这里把完整链路拆开讲清楚,顺带说说 MFC 消息映射的老写法。
整体思路
MFC 的菜单点击走的是"命令消息路由":菜单项被点击 → 生成 WM_COMMAND 消息 → 沿父窗口往子类找消息映射表 → 找到对应的 ON_COMMAND 就调用处理函数。所以要干三件事:
- 在头文件里声明处理函数;
- 在 cpp 的 消息映射表里注册这个命令 ID 和函数的对应关系;
- 写处理函数的实现。
三步缺一不可——只写实现不注册,点了没反应;只注册不声明,编译都过不去。
第一步:头文件里加声明
打开对话框类的头文件(比如 SEAL_PRESSUREDlg.h),在类里面加一行消息处理函数的声明:
class CSEAL_PRESSUREDlg : public CDialog
{
// ...
afx_msg void OnTypeManage();
// ...
};
afx_msg 是个宏,本质上就是给消息处理函数打的标记,用于 ClassWizard 识别。
第二步:cpp 里注册消息映射
找到同名的 cpp 文件里的 BEGIN_MESSAGE_MAP / END_MESSAGE_MAP 块:
BEGIN_MESSAGE_MAP(CSEAL_PRESSUREDlg, CDialog)
//{{AFX_MSG_MAP(CSEAL_PRESSUREDlg)
ON_COMMAND(ID_MENUITEM32771, OnTypeManage)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
这一行就是"当收到 ID_MENUITEM32771 这个命令时,调用 OnTypeManage"。资源 ID 要和菜单项的实际 ID 一致,这是最容易出错的地方。
关于 ID:用向导新建菜单项时 MFC 会自动分配 ID_MENUITEM32771 这种数字 ID,长得不好记。可以自己改资源编辑器里的 ID(比如改成 ID_MENU_TYPE_MANAGE),只要两边同步就行。
第三步:写处理函数
void CSEAL_PRESSUREDlg::OnTypeManage()
{
CTypDlg dlg;
dlg.DoModal();
}
DoModal() 是模态弹窗——弹出后焦点被它独占,关掉才回到主窗口。对另一个对话框来说一般就够用;如果目标是对话框之外的独立窗口,用 Create() 做非模态,那还要处理指针和销毁时机,麻烦一些。
ID 从哪来:资源编辑器那边
代码只是"接住"命令,菜单项本身要在资源视图里建:
- 打开 资源视图 → Menu,找到对应的菜单资源;
- 新增或选中一个菜单项,在属性面板里给 ID 赋值;
- 确认它的 Prompt 属性(鼠标悬停时状态栏提示)也填上,方便调试。
常见坑:菜单项的 ID 和按钮的 ID 不能重复,同一个 ID 被两个控件用,MFC 只会对先匹配到的那个响应。资源 ID 冲突可以在资源视图里查。
几个老版本 MFC 的注意点
//{{AFX_MSG_MAP 和 //}} 这两个注释块之间,是 ClassWizard 自动维护的区域,手改也能编译,但下次用向导可能会重写这一段——重要改动建议写在块外。
- VS 较新版本(2015+)的 MFC 支持新的
ON_COMMAND_IDR 类和 .ui 设计器,老教程里的 rc + 资源编辑器 思路仍然通用。
- 如果点了没反应,先在这行
ON_COMMAND 上打断点看有没有进;没进就是 ID 不匹配或消息没路由到这个窗口,检查菜单资源 ID。
DoModal 弹出的对话框类要在资源里也建好(对话框模板 ID + 对话框类),否则编译能过、运行直接崩。
把这三步串成一句口诀就是:头文件声明 → 映射表注册 → cpp 实现,再回头核对资源里的菜单 ID。工控项目里大量"加个菜单弹个窗"的需求,改的都是这一套。
qidao123.com企服评测-应用市场 编辑提示
本文由齐道123 IT 运维社区整理,说明 MFC 对话框中菜单命令响应与模态对话框弹出的实现步骤。代码为通用 MFC 消息映射写法,仅作技术讨论,不涉及任何第三方库或链接;请根据你使用的 Visual Studio 与 MFC 版本调整,并在修改资源 ID 前确认无重复冲突。
|