【WIN32之旅】给托盘图标加上MOUSE_ENTER、MOUSE_HOVER、MOUSE_LEAVE消息
2016-03-12 09:52
946 查看
转载请说明原出处,谢谢~ /article/7859363.html
相信很多人在WIN32项目开发过程中涉及到托盘相关处理时都会碰到这样一个问题,无法获取托盘图标的鼠标移入(Mouse Enter)、移出(Mouse Leave)以及悬停(Mouse Hover)消息,因为WINDOWS只提供了一个WM_MOUSEMOVE消息给我们,想要实现更为复杂的界面逻辑,就比如自绘的ToolTip提示或者消息预览窗口那可怎么办呢?
说到这里,我想大伙们心底里一定都异口同声地表示揪心,不过没关系,我们这群爱捣鼓的也不吃吃素的人,让我们先来分析一下这几个消息的核心产生因素,我们知道时间是线性的,而程序的执行也是随时间呈线性的,所以我们不妨从时间上来分析我们需要的这几个消息与WM_MOUSEMOVE之间的关系:
PS. 首先我们要明白鼠标只要在托盘图标RECT区域中移动就会产生WM_MOUSEMOVE消息。
1.WM_MOUSE_ENTER(ENTER在时间上的表现为鼠标从LEAVE转变为ENTER,即第一次收到WM_MOUSEMOVE时)
2.WM_MOUSE_HOVER (HOVER在时间上的表现为间隔一定时长鼠标HOVER位置不变,即鼠标位置等于最后一次收到WM_MOUSEMOVE时的位置)
3.WM_MOUSE_LEAVE(LEAVE则正好与ENTER过程相反,即鼠标从ENTER转为了LEAVE状态)
从上面我们的分析我们可将在时间上呈线性的WM_MOUSEMOVE消息分解出我们所需要的WM_MOUSE_ENTER、WM_MOUSE_HOVER、WM_MOUSE_LEAVE消息,因此我们只需要利用上WIN32的定时器,无论托盘图标是在底部工具栏上还是托盘溢出区上,这都是一种比通过各种复杂方法获取托盘图标RECT区域,或者使用单独线程进行检测更为简便的方法。
下面就上关键代码吧:
使用示例代码:
总而言之,虽然微软没有给我们所需要的检测鼠标进入、移出以及悬停托盘的消息,但只要我们静下心来认真思考仔细分析,我想我们总会会心一笑入浴春风,相信以上的内容能够帮助到正需要帮助的人。
相信很多人在WIN32项目开发过程中涉及到托盘相关处理时都会碰到这样一个问题,无法获取托盘图标的鼠标移入(Mouse Enter)、移出(Mouse Leave)以及悬停(Mouse Hover)消息,因为WINDOWS只提供了一个WM_MOUSEMOVE消息给我们,想要实现更为复杂的界面逻辑,就比如自绘的ToolTip提示或者消息预览窗口那可怎么办呢?
说到这里,我想大伙们心底里一定都异口同声地表示揪心,不过没关系,我们这群爱捣鼓的也不吃吃素的人,让我们先来分析一下这几个消息的核心产生因素,我们知道时间是线性的,而程序的执行也是随时间呈线性的,所以我们不妨从时间上来分析我们需要的这几个消息与WM_MOUSEMOVE之间的关系:
PS. 首先我们要明白鼠标只要在托盘图标RECT区域中移动就会产生WM_MOUSEMOVE消息。
1.WM_MOUSE_ENTER(ENTER在时间上的表现为鼠标从LEAVE转变为ENTER,即第一次收到WM_MOUSEMOVE时)
2.WM_MOUSE_HOVER (HOVER在时间上的表现为间隔一定时长鼠标HOVER位置不变,即鼠标位置等于最后一次收到WM_MOUSEMOVE时的位置)
3.WM_MOUSE_LEAVE(LEAVE则正好与ENTER过程相反,即鼠标从ENTER转为了LEAVE状态)
从上面我们的分析我们可将在时间上呈线性的WM_MOUSEMOVE消息分解出我们所需要的WM_MOUSE_ENTER、WM_MOUSE_HOVER、WM_MOUSE_LEAVE消息,因此我们只需要利用上WIN32的定时器,无论托盘图标是在底部工具栏上还是托盘溢出区上,这都是一种比通过各种复杂方法获取托盘图标RECT区域,或者使用单独线程进行检测更为简便的方法。
下面就上关键代码吧:
/******************************************************************************* * @file TrayIconHandler.hpp 2016\3\10 17:47:38 $ * @author Jeffrey Tse <JeffreyTse.mail@gmail.com> * @brief Trayicon message handle program. ******************************************************************************/ #define TRAYICON_HOVER_TIMER_ID 0x024 #define TRAYICON_LEAVE_TIMER_ID 0x025 class TrayIconHandler { public: enum _TrayIconMessage { WM_MOUSE_ENTER = 0x00F0, WM_MOUSE_HOVER, WM_MOUSE_LEAVE } TrayIconMessage public: TrayIconHandler(HWND hWnd, UINT uTrayIconMsg, UINT uHoverElapse = 300U) : m_hWnd(hWnd), m_uTrayIconMsg(uTrayIconMsg), m_uHoverElapse(uHoverElapse), m_bMouseEnter(FALSE){}; ~TrayIconHandler() { // 清除检测定时器 KillTimer(m_hMainHwnd, TRAYICON_HOVER_TIMER_ID); KillTimer(m_hMainHwnd, TRAYICON_LEAVE_TIMER_ID); }; LRESULT MessageNotify(TrayIconMessage uMsg) { // Do something ... } LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) { HRESULT lRes = S_OK; switch (uMsg) { case m_uTrayIconMsg: lRes = OnTrayIconMessage(uMsg, wParam, lParam); break; case WM_TIMER: lRes = OnTimer(uMsg, wParam, lParam); break; default: break; } return lRes; } LRESULT OnTrayIconMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(lParam) { case WM_RBUTTONDOWN: { } break; case WM_LBUTTONDBLCLK: { } break; ... case WM_MOUSEMOVE: { if(!m_bMouseEnter) { m_bMouseEnter = TRUE; // DEBUG_STRING(_T("################# TRAYICON_ENTER #################\r\n")) // Do something ... MessageNotify(TrayIconMessage::WM_MOUSE_ENTER); } POINT pt; if(GetCursorPos(&pt)) // 获取当前鼠标位置 { if(pt.x != m_ptMouseHover.x || pt.y != m_ptMouseHover.y) { // 重置检测定时器 KillTimer(m_hMainHwnd, TRAYICON_HOVER_TIMER_ID); KillTimer(m_hMainHwnd, TRAYICON_LEAVE_TIMER_ID); SetTimer(m_hMainHwnd, TRAYICON_HOVER_TIMER_ID, m_uHoverElapse, NULL); SetTimer(m_hMainHwnd, TRAYICON_LEAVE_TIMER_ID, 200U, NULL); // 记录鼠标位置 m_ptMouseHover = pt; } } } break; return S_OK; } LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam) { if(wParam == TRAYICON_HOVER_TIMER_ID) { KillTimer(m_hMainHwnd, TRAYICON_HOVER_TIMER_ID); POINT pt; if(GetCursorPos(&pt)) { if(pt.x == m_ptMouseHover.x && pt.y == m_ptMouseHover.y) { // DEBUG_STRING(_T("################# TRAYICON_HOVER #################\r\n")) // Do something ... MessageNotify(TrayIconMessage::WM_MOUSE_HOVER); } } } else if(wParam == TRAYICON_LEAVE_TIMER_ID) { POINT pt; if(GetCursorPos(&pt)) { if(pt.x != m_ptMouseHover.x || pt.y != m_ptMouseHover.y) { m_bMouseEnter = FALSE; KillTimer(m_hMainHwnd, TRAYICON_HOVER_TIMER_ID); KillTimer(m_hMainHwnd, TRAYICON_LEAVE_TIMER_ID); // DEBUG_STRING(_T("################# TRAYICON_LEAVE #################\r\n")) // Do something ... MessageNotify(TrayIconMessage::WM_MOUSE_LEAVE); } } } return S_OK; } private: HWND m_hMainHwnd; // 主消息窗口 UINT m_uTrayIconMsg; // 注册的托盘通知消息 UINT m_uHoverElapse; // 停留时长 BOOL m_bMouseEnter; // 鼠标是否进入 POINT m_ptMouseHover; // 鼠标停留位置 }
使用示例代码:
#include <windows.h> ... TrayIconHandler handler(g_hWnd, WM_TRAYICON_NOTIFY); ... // 窗口过程函数 LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch (uMsg) { case WM_DESTROY: // 窗口销毁消息 PostQuitMessage( 0 ); // 发送退出消息 return 0; } // 调用处理windows消息 handler.HandleMessage(uMsg, wParam, lParam); return DefWindowProc( hwnd, uMsg, wParam, lParam ); }
总而言之,虽然微软没有给我们所需要的检测鼠标进入、移出以及悬停托盘的消息,但只要我们静下心来认真思考仔细分析,我想我们总会会心一笑入浴春风,相信以上的内容能够帮助到正需要帮助的人。
相关文章推荐
- nyoj32---组合数
- python async/await
- C++设计模式编程中的迭代器模式应用解析
- Window On Top–让任意窗口位于顶层
- Mac文件系统
- android studio更新到1.5后遇到的问题
- 前后端分离开发部署模式
- 和GCD相关的“个数”及“求和”问题——hdu 2588、nyist 1007
- python asyncio
- QML中的BusyIndicator
- Eclipse在启动模拟器时出错
- Html5 手机wap开发、微信开发、APP开发的优缺点-创业者必知
- 漫谈架构2
- 网络爬虫个人博客
- CentOS 6.4下安装和配置Samba 第2页_服务器应用_Linux公社-Linux系统门户网站
- java,随机抽取
- Mysql 5.7免安装版配置 win10
- QML中有关image的相关属性
- Codeforces 651C Watchmen【模拟】
- HDU 3105 Fred's Lotto Tickets [Ad Hoc]