探索该消息的起因
在一个基于MFC的程序中,有个窗口是直接继承自CWnd,需要给这个窗口里添加相应的ToolTip,当鼠标进入窗口并且悬停在某些地方的时候需要显示ToolTip.
这个乍看起来实现很简单,重写MouseHover和MouseLeave就完事了,显示相应的ToolTip的逻辑就在这两个函数里面,于是自己在这个类里面的添加了相应函数以及相应的消息,并且写了实现逻辑。emm,按下F5之后,发现压根没有显示相应的ToolTip,调试之后发现MouseHover以及MouseLeave压根没有进去;心里一万个问好^^??
自以为正确的操作代码实现
在对应的头文件添加相应的函数
afx_msg void OnMouseMove(UINT nFlags, CPoint point); afx_msg void OnMouseLeave(); afx_msg void OnMouseHover(UINT nFlags, CPoint point);
在MESSAGE_MAP中添加相应的消息
ON_WM_MOUSELEAVE() ON_WM_MOUSEMOVE() ON_WM_MOUSEHOVER()
实现对应的函数,在这里我就直接将函数里面的功能逻辑改为doSomething了;
void CCMouseLeaveDlg::OnMouseMove(UINT nFlags, CPoint point) { dosomething(); } void CCMouseLeaveDlg::OnMouseLeave() { dosomething(); } void CCMouseLeaveDlg::OnMouseHover(UINT nFlags, CPoint point) { dosomething(); }
运行程序调试,看看是否会进入相应的鼠标消息函数
运行之后发现什么都没有做,调试也发现里面的消息函数压根没有进去!What's the hell!
面向谷歌寻求原因
Windows does not automatically send a WM_MOUSELEAVE message. When the mouse enters the control, you need to call **_TrackMouseEvent** to get it to notify you when this occurs
也就是说,为窗口添加WM_MOUSEHOVER或WM_MOUSELEAVE消息并不会响应,需要自己手动做一些特殊化处理,例如使用
TRACKMOUSEEVENT
TRACKMOUSEEVENT 做什么
对于这个函数,直接在MSDN上看相关文档,就可以得到函数的大概,TrackMouseEvent函数说明。
我看到里面有一条语句The function can post the following messages. 瞬间明白了为何这个函数可以用来出发MouseLeave消息以及MouseHover消息。这个函数可以触发的消息如下表所示,我这只是个搬运工哈哈^^
Message Description WM_NCMOUSEHOVER The same meaning as WM_MOUSEHOVER except this is for the nonclient area of the window WM_NCMOUSELEAVE The same meaning as WM_MOUSELEAVE except this is for the nonclient area of the window WM_MOUSEHOVER The mouse hovered over the client area of the window for the period of time specified in a prior call to TrackMouseEvent WM_MOUSELEAVE The mouse left the client area of the window specified in a prior call to TrackMouseEvent. All tracking requested by TrackMouseEvent is canceled when this message is generated.
TRACKMOUSEEVENT的 结构定义
这个结构体的具体定义参见官方文档TRACKMOUSEEVENT结构体
我个人觉得主要是dwFlags和dwHoverTime的设置,具体的参数可选项参考官方文档;下面给出我自己在使用的时候的一部分结构体设置代码实现
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE | TME_HOVER;
tme.hwndTrack = m_hWnd;
tme.dwHoverTime = 10;
m_bMouseTracking = _TrackMouseEvent(&tme);
# 正确的处理方法
自己在类中定义一个BOOL变量用来记录 鼠标状态,初始值为FALSE,我自己取得变量为m_bMouseTracking,这个变量的目的是为了防止鼠标已经在窗口上,移动鼠标就会不断产生WM_MOUSEHOVER消息;
而对于TRACKMOUSEEVENT的使用则是在MouseMove函数里进行,进行结构体的相关信息的设置,具体的实现如下,主要是加了TRACKMOUSEEVENT,用于发送WM_MOUSELEAVE和WM_MOUSEHOVER消息,从而执行相关的操作;
void CCMouseLeaveDlg::OnMouseMove(UINT nFlags, CPoint point)
{
if(!m_bMouseTracking)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE | TME_HOVER;
me.hwndTrack = m_hWnd;
tme.dwHoverTime = 10;
m_bMouseTracking = _TrackMouseEvent(&tme);
}
maybeDoSomething();
}
void CCMouseLeaveDlg::OnMouseLeave()
{
m_bMouseTracking = FALSE;
maybeDoSomethingElse();
}
void CCMouseLeaveDlg::OnMouseHover(UINT nFlags, CPoint point)
{
GetPositionOfToolTipControl();
ShowToolTip();
}
总结
自己一开始以为自己很快就能搞定,效果没出来的时候还以为是自己的写的代码有问题,导致自己调试代码调了好久,后来发现没有触发相应的消息之后,就直接面向谷歌了。这玩意一搜一堆,当时以为自己很快就有了解决办法,卧槽,当时自己也不明白这些参数和结构体是用来的干嘛的,直接全抄了,调试后发现依旧没用,直接导致怀疑人生。最后发现是dwFlags的参数选择了一个非客户区,导致不会再客户区发送相应的消息,直接GG。
最后面还是自己参考官方文档,了解每个参数的设置以及含义,才恍然大悟。最后,在遇到问题的时候不要慌,首先想想有什么解决方法没,没有的话在面向谷歌或者面向百度,这一步需要自己细心,不要生搬硬套,否则就会出现我上面那种傻子行为^^