当前位置:C++技术网 > 精选软件 > 鼠标悬停效果(WM_MOUSEHOVER和WM_MOUSELEAVE)的实现

鼠标悬停效果(WM_MOUSEHOVER和WM_MOUSELEAVE)的实现

更新时间:2016-11-11 21:07:08浏览次数:1+次

    我们可以看到,各种炫酷的软件界面、网页效果,鼠标经过悬停和离开都会有动态交互效果,是不是自己也想实现一下呢?当你兴奋勃勃的找到了WM_MOUSEHOVER和WM_MOUSELEAVE消息,然后处理这两个消息,结果发现,怎么根本就没有这两个消息过来。是不是很打击呢?必须很打击。之前我也就是这么被打击了,就没有去玩了。后来MFC Dui框架需要这个效果,所以就去研究了一下,这才有了这篇文章。

    这是为什么呢?WM_MOUSEHOVER和WM_MOUSELEAVE消息并不是标准的基本消息,这个消息属于衍生的一类消息了。所谓的WM_MOUSEHOVER悬停和WM_MOUSELEAVE离开消息,实际上有计时器在起作用。当鼠标移动到一个窗口上的时候,计时器开始计时,当时间到的时候,就发了WM_MOUSEHOVER消息,表示鼠标悬停在这个窗口上了。当鼠标移出了窗口,在这个动态的移动过程中,一旦检测到光标脱离了窗口的范围,就发一个WM_MOUSELEAVE消息。

    由上可见,WM_MOUSEHOVER和WM_MOUSELEAVE消息是动态处理的结果,需要计时器消息的参与。所以,这种消息代价还是很高的。一是占用的资源多,而是还要不停的计算。极端点,如果是很老的机器,说不定这个效果会卡卡的。当然对于现在的机器来说,那都不是事。但是这个消息默认是不启用的。所以你才会发现,直接处理中这两个消息,根本就没有用。

    下面是实现的效果图:

WM_MOUSEHOVER鼠标进入悬停消息

WM_MOUSELEAVE离开消息

    当鼠标进入客户区的时候,提示“鼠标已进入”,当鼠标离开客户区的时候提示“鼠标已离开”。这是一个基本的演示,你可以做很多事情哦。你想看很炫的效果,可以看下面的效果图:

绚丽的悬停效果

    只要你在检测到悬停的时候,处理一下WM_MOUSEHOVER消息即可。

    那么问题是,如何启动悬停和离开消息呢?

    这得先来了解一个结构体TRACKMOUSEEVENT,声明如下:


typedef struct tagTRACKMOUSEEVENT {
  DWORD cbSize;//结构体大小
  DWORD dwFlags;//标志,激活什么消息,一般是TME_HOVER和TME_LEAVE
  HWND  hwndTrack;//被跟踪的窗口句柄
  DWORD dwHoverTime;//悬停触发消息的时间
} TRACKMOUSEEVENT, *LPTRACKMOUSEEVENT;
     结构体的成员的含义,在声明中我已经标出来了。


    聪明的你,肯定也知道怎么去激活消息了。我们只要在dwFlags中指定要激活的消息,也就可以启动悬停效果了。启动了悬停效果,实际上,也就启动了鼠标跟踪事件。系统会时刻跟踪鼠标的移动,因此会比较耗费CPU,当然对于现代计算机来说,没有问题的。

    那么启动悬停消息即启动鼠标跟踪事件的函数为:TrackMouseEvent

    这个函数的声明如下:


BOOL TrackMouseEvent(LPTRACKMOUSEEVENT lpEventTrack);
     这个函数就一个参数,即前面介绍的结构体变量地址,是不是很简单。这个函数执行后,也就启动了鼠标跟踪事件。这样,系统就会在合适的时刻向对应的窗口PostMessage消息,消息就是dwFlags指定的消息哦。


    当然,在哪里启动消息,你想怎么玩就怎么玩。只不过还是要稍微考虑一下性能问题,万一电脑程序运行多了,会一卡卡的,让人不爽。所以,我们一般的做法是在鼠标移动的时候启用,然后用一个变量来记录状态。当鼠标悬停或者离开的时候,将状态改变一下。而且,根据这个状态,鼠标移动消息可以不要重复的启动鼠标跟踪事件。

    我们这里是用MFC实现的,你可以直接使用Win32处理WM_MOUSEHOVER和WM_MOUSELEAVE消息和WM_MOUSEMOVE实现。实现的代码如下:


void CHoverStatic::OnMouseHover(UINT nFlags, CPoint point)
{
    SetWindowText(_T("鼠标已进入"));
    m_bTrackLeave = FALSE;  
    CWnd::OnMouseHover(nFlags, point);
}
void CHoverStatic::OnMouseLeave()
{
    SetWindowText(_T("鼠标已离开"));
    m_bTrackLeave = FALSE;  
    CWnd::OnMouseLeave();
}
void CHoverStatic::OnMouseMove(UINT nFlags, CPoint point)
{
    if (!m_bTrackLeave)  
    {  
        TRACKMOUSEEVENT tme;  
        tme.cbSize = sizeof(tme);  
        tme.hwndTrack = m_hWnd;  
        tme.dwFlags = TME_LEAVE|TME_HOVER;  
        tme.dwHoverTime = 50;  
        m_bTrackLeave = TrackMouseEvent(&tme);  
    }
    CWnd::OnMouseMove(nFlags, point);
}
     这么分析了之后,相信一看就懂了。