控件的通知消息被送到哪里去了?

fangxu1999 2008-03-26 12:05:49
我从CComboBox类派生出一个自定义的类CMyCombobox,主要用来实现根据编辑框的内容进行筛选列表框中的数据项的功能,例如:在创建时将所有可能的数据都存进去,当编辑框中输入A,则列表框中将所有以A打头的都列出来。
使用了ON_CONTROL_REFLECT(CBN_EDITCHANGE, OnEditchange)在列表框中进行了处理,此时当Edit内容改变时,列表框能够相应该消息。
我把这个自定义的组合框放到了对话框中,然后通过一个Button向组合框发送CBN_EDITCHANGE,发现无论是组合框还是对话框都不响应这个消息,不知道消息究竟被送到哪里处理了。

//对话框中按钮发消息
void CMyDlg::OnButton1()
{
SendDlgItemMessage(IDC_COMBO1, CBN_EDITCHANGE, IDC_COMBO1, (LPARAM)(GetDlgItem(IDC_COMBO1)->GetSafeHwnd()));
}

//对话框来处理消息
ON_CBN_EDITCHANGE(IDC_COMBO1, OnEditchangeCombo1)
void CMyDlg::OnEditchangeCombo1()
{
AfxMessageBox("CDlgTestDlg::OnEditchangeCombo1");
}

//组合框本身来处理消息
ON_CONTROL_REFLECT(CBN_EDITCHANGE, OnEditchange)
void CMyCombobox::OnEditchange()
{
AfxMessageBox("OnEditchange");
}

如果使用SendDlgItemMessage(.., WM_CHAR, ..)之类的Windows消息,测试发现是由组合框本身处理的,即使对话框也提供了处理方法,这是由于消息被发往了组合框窗口过程,很容易理解。可是如果是发送的控件通知消息,虽然是向控件发的,但是通知消息本身又是通知其父窗口的,父窗口又会反射消息...,确实搞糊涂了,请问一下控件的通知消息到底是怎么路由传递的?它和命令消息WM_COMMAND有什么区别啊?MSDN上好像说是实际上就是发的WM_COMMAND消息。而命令消息就会直接调用OnCommand进行处理了,应该不会向外发的。针对这里的情况,能不能有一个好的说明,到底CBN_EDITCHANGE被送到哪里去了啊?
谢谢指点。
...全文
354 20 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
wwwhhb4002 2009-03-03
  • 打赏
  • 举报
回复

学习
吹雪 2008-04-02
  • 打赏
  • 举报
回复

BOOL PASCAL CWnd::ReflectLastMsg(HWND hWndChild, LRESULT* pResult)
{
// get the map, and if no map, then this message does not need reflection
CHandleMap* pMap = afxMapHWND();
if (pMap == NULL)
return FALSE;

// check if in permanent map, if it is reflect it (could be OLE control)
CWnd* pWnd = (CWnd*)pMap->LookupPermanent(hWndChild);
ASSERT(pWnd == NULL || pWnd->m_hWnd == hWndChild);
if (pWnd == NULL)
{
#ifndef _AFX_NO_OCC_SUPPORT
// check if the window is an OLE control
CWnd* pWndParent = (CWnd*)pMap->LookupPermanent(::GetParent(hWndChild));
if (pWndParent != NULL && pWndParent->m_pCtrlCont != NULL)
{
// If a matching control site exists, it's an OLE control
COleControlSite* pSite = (COleControlSite*)pWndParent->
m_pCtrlCont->m_siteMap.GetValueAt(hWndChild);
if (pSite != NULL)
{
CWnd wndTemp(hWndChild);
wndTemp.m_pCtrlSite = pSite;
LRESULT lResult = wndTemp.SendChildNotifyLastMsg(pResult);
wndTemp.m_hWnd = NULL;
return lResult;
}
}
#endif //!_AFX_NO_OCC_SUPPORT
return FALSE;
}

// only OLE controls and permanent windows will get reflected msgs
ASSERT(pWnd != NULL);
return pWnd->SendChildNotifyLastMsg(pResult);
}

zaodt 2008-03-26
  • 打赏
  • 举报
回复

楼主有空可以看看这本书:

『Windows程序设计』,下载地址:

http://blog.csdn.net/zaodt/archive/2007/11/25/1901332.aspx
zaodt 2008-03-26
  • 打赏
  • 举报
回复

MSDN:

The CBN_EDITCHANGE notification message is sent after the user has taken an action that may have altered the text in the edit control portion of a combo box.


The parent window of the combo box receives this notification message through the WM_COMMAND message.


当用户改变编辑框中的内容时,控件的父窗口会收到【CBN_EDITCHANGE】消息;

父窗口的回调函数会响应【WM_COMMAND】进行处理。
Torch009 2008-03-26
  • 打赏
  • 举报
回复
1楼的正确。
yxz_lp 2008-03-26
  • 打赏
  • 举报
回复
SendMessage(WM_COMMAND , MAKEWPARAM(IDC_COMBO1,CBN_EDITCHANGE), (LPARAM)(GetDlgItem(IDC_COMBO1)->GetSafeHwnd()));
cnzdgs 2008-03-26
  • 打赏
  • 举报
回复
你按下面的方式处理,不需要Button。
class CMyComboBox : public CComboBox
{
DECLARE_DYNAMIC(CMyComboBox)
protected:
DECLARE_MESSAGE_MAP()
virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam);
};

IMPLEMENT_DYNAMIC(CMyComboBox, CComboBox)

BEGIN_MESSAGE_MAP(CMyComboBox, CComboBox)
END_MESSAGE_MAP()

BOOL CMyComboBox::OnCommand(WPARAM wParam, LPARAM lParam)
{
if (HIWORD(wParam) == EN_CHANGE)
MessageBox(_T("OK"));
return CComboBox::OnCommand(wParam, lParam);
}
fangxu1999 2008-03-26
  • 打赏
  • 举报
回复
确实如上面那样,我们也可以使用CWnd::SendDlgItemMessage(id, msg, wparam,lparam)直接向Combobox发CBN_EDITCHANGE了,虽然道理上有点说不通。

在父窗口的OnCommand中,会首先调用子控件的OnChildNotify方法,如果在此实现了对某些消息的处理工作,并返回TRUE即可。如果没有处理,则会调用默认的控件所继承的类的OnChildNotify方法,这里当然是CCombobox::OnChildNotify方法。这个父类的方法有一些通用的默认处理操作,还可以根据在消息映射表中所注册的条目进行查找,处理我们已经给出映射的消息。如果这样都还找不到处理的该消息的办法,那么就回到父窗口的OnCommand,在父窗口中进行通常的处理了。

参考了http://blog.csdn.net/txdog/archive/2007/08/18/1749841.aspx 只是没有看到CWnd::OnNotify的使用,因为根本进不去. OnCommand->OnChildNotify->ON_NOTIFY_REFLECT->OnCommand。而使用新的控件(如Datatimepicker)就可以收到WM_NOTIFY消息,但此时却又收不到WM_COMMAND了,只能调用CWnd::OnNotify。

调了很久,终于有点眉目,可以小节了。如果控件自己需要处理消息,需要改写控件的OnChildNotify或是ON_NOTIFY_REFLECT提供通知反射处理。
之前我主要出现的问题就在于对通知消息的实质没有掌握清楚,CBN_EDITCHANGE仅仅是一个通知码,需要作为其中的WPARAM的一部分进行发送,真正的消息应该是WM_COMMAND。

还请高手解释一下问什么消息从 源自于Edit的EN_CHANGE通知消息给Combobox 变成了 源自于Combobox的CBN_EDITCHANGE通知消息给CDialog的了?(调试的结果见16楼)

谢谢关注。
fangxu1999 2008-03-26
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 cnzdgs 的回复:]
你这种测试的想法是错的,ComboBox的内容改变是由它来通知其父窗口的,而不是由外部控件来通知它。
ComboBox内部包含了一个EDIT控件,EDIT控件的内容改变时会发消息给ComboBox,你在派生的ComboBox中响应EN_CHANGE消息试试。
[/Quote]


按道理确实需要如此处理,通知消息是通知外面父窗口的。可是不晓得::SendMessage怎么搞的,我发源自于Edit的EN_CHANGE通知消息给Combobox,通过系统API ::SendMessage发过去,在User32中不晓得怎么转悠的,当到了AfxWndProcBase的时候竟然变成了源自于Combobox的CBN_EDITCHANGE通知消息给CDialog了。具体结果如下:
在CDialog::OnButton1使用::SendMessage的几个参数值和解释
hWnd = 0x002805d8 //HANDLE of CComboBox
nMsg = 0x0111 //WM_COMMAND
wParam = 0x0300 03e9 //EN_CHANGE + ID of CEdit
lParam = 0x026e0658 //HANDLE of CEdit

in USER32

AfxWndProcBase中所收到的参数值和解释
hWnd = 0x00df04ac //HANDLE of CDialog
nMsg = 0x0111 //WM_COMMAND
wParam = 0x0005 03f1 //CBN_EDITCHANGE + ID of CComboBox
lParam = 0x002805d8 //HANDLE of CComboBox

除了消息不变之外,WM_COMMAND,其他都不同了,不晓得怎么回事。因为这样的话就不能交给Combobox了,是交给CDialog的。
cnzdgs 2008-03-26
  • 打赏
  • 举报
回复
是WM_COMMAND消息中的EN_CHANGE通知。
cnzdgs 2008-03-26
  • 打赏
  • 举报
回复
你这种测试的想法是错的,ComboBox的内容改变是由它来通知其父窗口的,而不是由外部控件来通知它。
ComboBox内部包含了一个EDIT控件,EDIT控件的内容改变时会发消息给ComboBox,你在派生的ComboBox中响应EN_CHANGE消息试试。
fangxu1999 2008-03-26
  • 打赏
  • 举报
回复
现在最想知道的就是:
//对话框中按钮发消息
void CMyDlg::OnButton1()
{
//是满足CWnd::SendDlgItemMessage的调用约定
SendDlgItemMessage(IDC_COMBO1, CBN_EDITCHANGE, IDC_COMBO1, (LPARAM)(GetDlgItem(IDC_COMBO1)->GetSafeHwnd()));
}

//对话框来处理消息
ON_CBN_EDITCHANGE(IDC_COMBO1, OnEditchangeCombo1)
void CMyDlg::OnEditchangeCombo1()
{
AfxMessageBox("CDlgTestDlg::OnEditchangeCombo1");
}

//组合框本身来处理消息
ON_CONTROL_REFLECT(CBN_EDITCHANGE, OnEditchange)
void CMyCombobox::OnEditchange()
{
AfxMessageBox("OnEditchange");
}

这个CBN_EDITCHANGE消息去哪里了?这两处可都没有收到
fangxu1999 2008-03-26
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 cnzdgs 的回复:]
你现在的按钮是做什么用的?是ComboBox和Button组成复合控件吗?
[/Quote]

现在在测试问题,搞懂之后就可以真正开始写代码了啊。
这是一个简单的基于对话框的程序。
一个普通的按钮,一个组合框,只不过这个组合框是和我自己派生出来的CMyCombobox的成员对象绑定在一起的。在CMyCombobox这个类中,提供了=CBN_EDITCHANGE处理方法。而在外面的对话框中也提供了CBN_EDITCHANGE的处理方法。处理方法都很easy,就是AfxMessageBox()。
那个按钮就是想发一个消息告诉组合框,你的内容改变了,请你自己更新一下列表内容——就是发出CBN_EDITCHANGE通知,不过我不想通知对话框,而是想告诉组合框自己。
(一般情况下,是组合框通知外面。而我想组合框通知它自己)
cnzdgs 2008-03-26
  • 打赏
  • 举报
回复
你现在的按钮是做什么用的?是ComboBox和Button组成复合控件吗?
fangxu1999 2008-03-26
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 cnzdgs 的回复:]
在Windows中消息通常都是从子窗体发向其父窗体的,你应该在对话框中响应CBN_EDITCHANGE通知,然后调ComboBox类的函数或者再向ComboBox发消息。
[/Quote]

我也知道这样做确实很简单。但是我是希望做出一个相对独立的组合框。创建的时候通过某种方法喂一些数据,然后就可以让他自己处理自己的事了。不用外部干涉了啊
cnzdgs 2008-03-26
  • 打赏
  • 举报
回复
在Windows中消息通常都是从子窗体发向其父窗体的,你应该在对话框中响应CBN_EDITCHANGE通知,然后调ComboBox类的函数或者再向ComboBox发消息。
fangxu1999 2008-03-26
  • 打赏
  • 举报
回复
谢谢各位,不过如果使用CWnd::SendMessage(WM_COMMAND,...)将通知码放到WPARAM中,我感觉实际上是向父窗口CMyDialog发的通知消息,通知父窗口“组合框的内容发生了变化,请求处理”,然后试图让父窗口处理或转交给子窗口处理。
而测试的结果是父窗口——对话框直接处理了该消息,没有使用反射机制ON_CONTROL_REFLECT(CBN_EDITCHANGE, OnEditchange)交给子窗口——组合框来处理。看了代码执行过程发现也没有进入到ReflectLastMsg这个过程中去,也就是说没有机会给子窗口处理。

这样就不能达到让组合框自己本身来处理逻辑上应该属于自身的操作了

我认为CWnd::SendDlgItemMessage(IDC,...)是首先取出CWnd中制定IDC的控件的窗口句柄,然后直接向这个解析出来的窗口发消息,那么就会交给这个解析出来的子窗口来处理。不知道理解得对不对??

我所希望的是:要么向子窗口直接发命令(这样最好);要么通知父窗口但是通过反射之后还是交给子窗口处理。
如果向子窗口直接发命令的话,以上理解如果正确的话,大概必须CWnd::SendDlgItemMessage
而如果是通过反射机制,那么消息就先要流到父窗口处,然后ReflectLastMsg到子窗口,子窗口处理后就直接返回了,这样的话就应该使用CWnd::SendMessage(向this发消息)了。

对Windows消息很疑惑,想搞清楚。请大家帮忙解惑,谢谢。
菜牛 2008-03-26
  • 打赏
  • 举报
回复
CComboBox本来有个FindSting方法好像就可以啊。
yxq123 2008-03-26
  • 打赏
  • 举报
回复
MFC消息机制,系统会给每个应用程序创建一个消息队列,这个消息队列应用程序会循环调用。应用程序的大部分消息都进入这个队列。
cnzdgs 2008-03-26
  • 打赏
  • 举报
回复
SendMessage(WM_COMMAND, MAKEWPARAM(IDC_COMBO1, CBN_EDITCHANGE), (LPARAM)(::GetDlgItem(m_hWnd, IDC_COMBO1)));

在MSDN中输入CBN_EDITCHANGE来查看相关说明。
目 录 译者序 前言 第一部分 基础知识 第1章 窗口 2 1.1 窗口和API环境 2 1.1.1 三种类型窗口 2 1.1.2 客户区和非客户区 3 1.2 窗口和MFC环境 4 1.3 怎样应用MFC创建一个窗口 5 1.4 怎样使用MFC销毁一个窗口 9 1.4.1 捆绑到一个已有的窗口 9 1.4.2 窗口类 10 1.4.3 窗口进程 10 1.5 怎样使用MFC创建一个窗口类 11 1.5.1 使用AfxRegisterWndClass () 函数注册一个窗口类 11 1.5.2 使用AfxRegisterClass ()函数 创建一个窗口类 12 1.6 怎样销毁一个MFC窗口类 14 1.7 厂商安装的窗口类 14 1.8 其他类型窗口 15 1.9 桌面窗口 16 1.10 小结 16 第2章 类 18 2.1 基类 18 2.1.1 CObject 18 2.1.2 CCmdTarget 19 2.1.3 CWnd 19 2.2 应用程序、框架、文档和视图类 19 2.2.1 CWinApp(O/C/W) 20 2.2.2 CView (O/C/W) 21 2.3 其他用户界面类 22 2.3.1 通用控件类 23 2.3.2 菜单类 23 2.3.3 对话框类 24 2.3.4 控制条类 24 2.3.5 属性类 25 2.4 绘图类 25 2.4.1 设备环境类 25 2.4.2 图形对象类 25 2.5 文件类 26 2.6 数据库类 26 2.6.1 ODBC类 26 2.6.2 DAO类 27 2.7 数据集类 27 2.8 其他数据类 27 2.9 通信类 28 2.10 其他类 29 2.11 小结 31 第3章 消息处理 32 3.1 发送或寄送一个消息 32 3.1.1 发送一个消息 32 3.1.2 寄送一个消息 32 3.1.3 发送一个消息与寄送一个消息 的比较 32 3.2 怎样使用MFC发送一个消息 33 3.3 怎样用MFC寄送一个消息 33 3.4 三种类型的消息 34 3.4.1 窗口消息 34 3.4.2 命令消息 34 3.4.3 控件通知 34 3.5 MFC怎样接收一个寄送的消息 36 3.6 MFC怎样处理一个接收到的消息 36 3.7 处理用户界面的对象 44 3.8 创建自定义窗口消息 45 3.8.1 静态分配的窗口消息 45 3.8.2 动态分配的窗口消息 46 3.9 重定向消息 47 3.9.1 子分类和超分类 47 3.9.2 用MFC子分类窗口 48 3.9.3 重载OnCmdMsg ( ) 49 3.9.4 使用SetWindowsHookEx ( ) 49 3.9.5 使用SetCapture ( ) 49 3.9.6 专有的消息泵 50 3.10 小结 50 第4章 绘图 51 4.1 设备环境 51 4.2 在MFC环境中创建一个设备环境 52 4.2.1 屏幕 52 4.2.2 打印机 53 4.2.3 内存 54 4.2.4 信息 54 4.3 绘图例程 55 4.3.1 画点 55 4.3.2 画线 55 4.3.3 画形状 55 4.3.4 形状填充和翻转 55 4.3.5 滚动 56 4.3.6 绘制文本 56 4.3.7 绘制位图和图标 56 4.4 绘图属性 56 4.4.1 设备环境属性 57 4.4.2 画线属性 58 4.4.3 形状填充属性 58 4.4.4 文本绘制属性 58 4.4.5 映像模式 59 4.4.6 调色板属性 62 4.4.7 混合属性 62 4.4.8 剪裁属性 63 4.4.9 位图绘制属性 64 4.5 元文件和路径 65 4.5.1 元文件 65 4.5.2 路径 66 4.6 颜色和调色板 66 4.6.1 抖动色 67 4.6.2 未经抖动色 67 4.6.3 系统调色板 67 4.6.4 使用系统调色板 68 4.6.5 动画色 71 4.7 控制什么时候在哪里绘图 71 4.7.1 处理WM_PAINT 71 4.7.2 只绘制被无效化的区域 72 4.7.3 处理WM_DRAWITEM 72 4.7.4 在其他时间绘图 73 4.8 小结 74 第二部分 用户界面实例 第5章 应用程序与环境 76 5.1 例1 规划MFC应用程序 76 5.2 例2 用AppWizard创建一个MFC 应用程序 79 5.3 例3 用ClassWizard创建一个类 83 5.4 例4 初始化应用程序屏幕 84 5.5 例5 保存应用程序屏幕 86 5.6 例6 处理命令行选项 88 5.7 例7 动态改变应用程序图标 91 5.8 例8 提示用户优先选项 93 5.9 例9 保存和恢复用户优先选项 97 5.10 例10 终止应用程序 100 5.11 例11 创建一个启动窗口 101 第6章 菜单 107 6.1 例12 使用菜单编辑器 107 6.2 例13 添加一个菜单命令处理函数 109 6.3 例14 根据当前可视文档动态改 变菜单 110 6.4 例15 启用和禁用菜单命令 111 6.5 例16 复选标记菜单命令 112 6.6 例17 单选标记菜单命令 113 6.7 例18 动态修改菜单 114 6.8 例19 动态修改系统菜单 116 6.9 例20 触发一个菜单命令 117 6.10 例21 创建弹出式菜单 117 第7章 工具栏和状态栏 120 7.1 例22 使用工具栏编辑器 120 7.2 例23 启用和禁用工具栏按钮 122 7.3 例24 为工具栏按钮添加字 123 7.4 例25 非标准工具栏大小 128 7.5 例26 保持工具栏按钮按下 129 7.6 例27 保持工具栏按钮组中 一个按钮按下 130 7.7 例28 为工具栏添加非按钮控件 131 7.8 例29 修改应用程序的状态栏 136 7.9 例30 更新状态栏窗格 138 7.10 例31 为状态栏添加其他控件 139 第8章 视图 145 8.1 例32 滚动视图 145 8.2 例33 改变鼠标光标形状 147 8.3 例34 沙漏光标 148 8.4 例35 窗体视图 149 8.5 例36 列表视图 152 8.6 例37 动态分割一个视图 163 第9章 对话框和对话条 166 9.1 例38 使用对话框编辑器 166 9.2 例39 创建一个对话框类 168 9.3 例40 模式对话框 170 9.4 例41 无模式对话框 171 9.5 例42 在无模式对话框的控件间 切换焦点 172 9.6 例43 对话框中的动画 173 9.7 例44 消息框 174 9.8 例45 对话条 176 第10章 控件窗口 182 10.1 例46 在任意位置创建一个控 件窗口 182 10.2 例47 用子分类定制一个通用 控件窗口 183 10.3 例48 用超分类定制一个通用 控件窗口 188 10.4 例49 在按钮上放置位图 190 10.5 例50 动态填充一个组合框 192 10.6 例51 排序一个列表控件 194 10.7 例52 分隔线控件 196 第11章 绘图 198 11.1 例53 绘制图形 198 11.2 例54 绘制文本 201 11.3 例55 从任意位置装入一个图 标并绘制 203 11.4 例56 从任意位置装入一个位 图和绘制一个位图 204 11.5 例57 从文件中创建一个位图 206 11.6 例58 创建一个自绘位图 211 第三部分 内部处理实例 第12章 消息 215 12.1 例59 添加消息处理函数或重 载MFC类 216 12.2 例60 添加命令范围消息处理函数 219 12.3 例61 重定向命令消息 221 12.4 例62 创建自己的窗口消息 222 第13章 文件、串行化和数据库 225 13.1 例63 访问二进制文件 225 13.2 例64 访问标准I/O文件 227 13.3 例65 访问内存文件 228 13.4 例66 在数据类中实现串行化 229 13.5 例67 串行化SDI或MDI文档 235 13.6 例68 按要求串行化 240 13.7 例69 透明地更新串行化的文档 242 13.8 例70 串行化多态类 246 13.9 例71 串行化数据集 248 13.10 例72 访问ODBC数据库 252 13.11 例73 访问DAO数据库 257 第14章 杂类 263 14.1 例74 剪切、拷贝和粘贴文本 数据 263 14.2 例75 剪切、拷贝、粘贴多信 息文本数据 268 14.3 例76 剪切、拷贝和粘贴二进制 数据 273 14.4 例77 数组函数 280 14.5 例78 列表函数 281 14.6 例79 映像函数 283 14.7 例80 系统键盘输入 285 14.8 例81 时间 288 第四部分 打包实例 第15章 库 291 15.1 例82 静态链接C/C++库 291 15.2 例83 动态链接C/C++库 295 15.3 例84 动态链接MFC扩展类库 300 15.4 例85 资源库 303 第五部分 附录 附录A 控件窗口风格 305 附录B 消息控件通知消息映像宏 323 附录C 访问其他应用程序类 328 附录D 开发中注意事项 330 附录E MFC快速参考指南 339

16,548

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • AIGC Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧