实话说,刚开始做视觉,那时候自己写框架,还经常不会用子窗口调用主窗口;指针也用不起来,所以,每次,最终的解决方法就是用消息传递。刚开始在书上看是基于消息响应,其实不太明白干啥的。现在理解的就是,你需要和某人建立关系,然后你俩需要一个指令,这个指令就是消息传递函数,具体传的啥,就看你函数写啥就会执行响应的动作,但是需要知道是谁给谁传递。所以就有一些主从关系和函数在。
两年前看QT的框架,发现槽函数和消息响应机制其实都差不多;可惜,当时做的框架也不知道去哪了,现在已经把QT忘光了。等改天有空,找出来好好学习拾起来QT。
DEEPSEEK搜MFC中的消息响应机制:
在 MFC(Microsoft Foundation Classes)框架中,消息响应机制是其核心设计之一,用于处理 Windows 窗口消息(如鼠标事件、键盘输入、控件通知等)。MFC 通过**消息映射(Message Map)**将 Windows 消息与对应的处理函数绑定,简化了传统 Win32 API 的复杂消息处理流程。以下是其核心要点:
1. MFC 消息机制的基础模型
- 消息来源:Windows 系统生成的消息(如
WM_PAINT
,WM_COMMAND
)。 - 消息接收者:MFC 窗口类(如
CWnd
派生类)或应用程序类(CWinApp
)。 - 消息路由:通过消息映射表将消息分发给对应的处理函数。
2. 消息处理流程
(1) 消息循环(Message Pump)
- 位置:
CWinApp::Run()
中实现。 - 作用:循环从系统消息队列中获取消息(
GetMessage
),并通过DispatchMessage
分发到目标窗口。while (GetMessage(&msg, nullptr, 0, 0)) { TranslateMessage(&msg); // 转换键盘消息(如 WM_CHAR) DispatchMessage(&msg); // 分发到窗口过程 }
(2) 窗口过程(Window Procedure)
- MFC 封装了默认的窗口过程
AfxWndProc
,通过消息映射表将消息路由到对应的类成员函数。 - 关键步骤:
- 收到消息后,MFC 查找目标对象(窗口或控件)的消息映射表。
- 根据消息类型(如
WM_COMMAND
)和标识符(如按钮 ID),调用对应的处理函数。
3. 消息映射(Message Map)
(1) 定义消息映射表
- 在类的头文件(
.h
)中声明消息处理函数,并使用DECLARE_MESSAGE_MAP()
宏。 - 在实现文件(
.cpp
)中使用宏绑定消息与处理函数:BEGIN_MESSAGE_MAP(CMyDialog, CDialogEx) ON_WM_PAINT() // 处理 WM_PAINT 消息 ON_COMMAND(ID_BUTTON1, &CMyDialog::OnButton1Clicked) // 处理按钮点击 ON_MESSAGE(WM_MYCUSTOM, &CMyDialog::OnMyCustomMessage) // 自定义消息 END_MESSAGE_MAP()
(2) 常见消息类型
- 窗口消息:以
ON_WM_XXX
宏绑定(如ON_WM_PAINT()
)。 - 命令消息:控件或菜单触发的
WM_COMMAND
,通过ON_COMMAND
绑定。 - 通知消息:控件的特定事件(如列表框选择变化),通过
ON_NOTIFY
绑定。 - 自定义消息:使用
ON_MESSAGE
宏处理用户定义的WM_APP + n
消息。
4. 消息处理函数
- 函数签名:返回
LRESULT
,参数为WPARAM
和LPARAM
(或特定参数类型)。 - 示例:
// 处理 WM_PAINT 消息 void CMyView::OnPaint() { CPaintDC dc(this); // 自动调用 BeginPaint/EndPaint dc.TextOut(10, 10, L"Hello MFC"); } // 处理按钮点击(WM_COMMAND) void CMyDialog::OnButton1Clicked() { MessageBox(L"Button clicked!"); } // 处理自定义消息 LRESULT CMyDialog::OnMyCustomMessage(WPARAM wParam, LPARAM lParam) { // 自定义逻辑 return 0; }
5. 关键技术细节
(1) 消息路由优先级
- MFC 消息路由顺序:
- 当前活动窗口(如对话框)。
- 应用程序主框架窗口(
CFrameWnd
)。 - 应用程序类(
CWinApp
)。
(2) 命令消息的特殊性
WM_COMMAND
消息支持通过ON_UPDATE_COMMAND_UI
动态更新 UI(如禁用按钮):void CMyView::OnUpdateFileSave(CCmdUI* pCmdUI) { pCmdUI->Enable(m_bIsModified); // 根据条件启用/禁用菜单项 }
(3) 消息预处理
- 使用
PreTranslateMessage
拦截消息(如全局快捷键):BOOL CMyApp::PreTranslateMessage(MSG* pMsg) { if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_F1) { ShowHelp(); // 自定义处理 return TRUE; // 阻止消息继续传递 } return CWinApp::PreTranslateMessage(pMsg); }
6. 常见问题与调试
- 消息未响应:
- 检查消息映射宏是否正确定义(如拼写错误)。
- 确保类的基类在
BEGIN_MESSAGE_MAP
中正确指定。
- 自定义消息未触发:
- 使用
RegisterWindowMessage
注册唯一消息标识符(避免冲突)。
- 使用
- 死锁或卡顿:
- 避免在消息处理函数中执行耗时操作(应使用多线程)。
7. MFC 消息机制 vs 通用事件驱动
特性 | MFC 消息机制 | 通用事件驱动(如 C#) |
---|---|---|
绑定方式 | 静态消息映射宏 | 事件委托(delegate /event ) |
灵活性 | 需要手动管理消息映射 | 自动代码生成(IDE 支持) |
适用场景 | 传统 Windows 桌面应用 | 现代框架(WPF、WinForms) |
调试复杂度 | 高(需手动跟踪消息流) | 低(可视化调试工具) |
通过 MFC 的消息映射机制,开发者可以高效处理 Windows 消息,但其设计较为底层,需熟悉宏和消息路由规则。现代框架(如 Qt 或 WPF)提供了更高级的抽象,但 MFC 仍是维护旧代码或开发轻量级 Windows 应用的重要工具。
自己使用记录:
实现的功能是:
两个窗口之间传递消息。
定义窗口:g_HwndCamWindow,给谁说话
定义一个消息:WM_CAM_TO_MAIN ,咱俩要有一次说话这件事
消息内容是啥:(消息函数:这里是AutoRuns),这件事就是具体说啥
调用消息:PostMessage,啥时说
StructCommon.h
#define WM_CAM_TO_MAIN (WM_USER+112)
在Global.h中
extern HWND g_HwndCamWindow;
在主框架类中:
newApplication.cpp
因为每个都要包含这个,
给他初始化
HWND g_HwndCamWindow=NULL;
在使用的主类中DlgMain.h
afx_msg LRESULT AutoRuns(WPARAM wp, LPARAM lp);
在使用的主类中DlgMain.cpp
消息映射函数中定义函数
BEGIN_MESSAGE_MAP(CDlgMain, CDialogEx)
ON_MESSAGE(WM_CAM_TO_MAIN, &CDlgMain::AutoRuns)
END_MESSAGE_MAP()
初始化中给初始化
g_HwndCamWindow = this->GetSafeHwnd();
并写一个消息函数
LRESULT CDlgMain::AutoRuns(WPARAM wp, LPARAM lp)
{
m_Section1.Lock();
AutoRun(1);
m_Section1.Unlock();
return 0;
}
DlgCamera.cpp
在使用的地方调用
::PostMessage(g_HwndCamWindow,WM_CAM_TO_MAIN,0,0);
通过这个WM_CAM_TO_MAIN消息可以在DlgCamera.cpp中给DlgMain.cpp中发送消息传话。
个人理解,记录备用。