前言:我之所以将这两个部分放在一起写,当然是因为他们是有关系的啦,我们的窗口是不会响应WM_MOUSELEAVE和WM_MOUSEHOVER消息的,我们可以通过_TrackMouseEvent来激活这两个消息,让我们的窗口接收这两个消息,接收到消息后,我们能干嘛呢????注意WM_MOUSEHOVER消息,当我们在一个控件上停一段时间后,就会激发这个消息,这个消息应该叫“悬停”,所以,在鼠标悬停时,我们应该创建toolTip!!!!这就是两者的关系。我们先看_TrackMouseEvent是如何激活这两个消息的,然后再看怎样添加ToolTip。
先看个最终界面图,吸引下大家


一、_TrackMouseEvent

默认情况下,窗口是不响应 WM_MOUSELEAVE 和 WM_MOUSEHOVER 消息的,所以要使用_TrackMouseEvent函数来激活这两个消息。调用这个函数后,当鼠标在指定窗口上停留超过一定时间或离开窗口后,该函数会 Post 这两个消息到指定窗口。

1、添加头文件和库

在stdafx.h中,添加所需要的头文件和库文件,代码如下:

#include <CommCtrl.h>
#pragma   comment(lib,   "comctl32.lib")

2、使用方法

(1)在对话框类中定义一个变量来标识是否追踪当前鼠标状态,之所以要这样定义是要避免鼠标已经在窗体之上时,一移动鼠标就不断重复产生 WM_MOUSEHOVER 。并初始化为false,意思是尚未开始追踪!

bool m_bMouseTracking;//追踪WM_MOUSELEAVE 和 WM_MOUSEHOVER 消息

(2)在WM_MOUSEMOVE中开启追踪

   case WM_MOUSEMOVE:{// Start tracking this entire window again...if( !m_bMouseTracking ) {//如果没有跟踪消息,则开启跟踪WM_MOUSEHOVER和WM_MOUSELEAVE消息TRACKMOUSEEVENT tme = { 0 };tme.cbSize = sizeof(TRACKMOUSEEVENT);tme.dwFlags = TME_HOVER | TME_LEAVE;tme.hwndTrack = m_hWnd;// 指定要 追踪 的窗口 tme.dwHoverTime = 10;// 鼠标在按钮上停留超过 10ms ,才认为状态为 HOVER_TrackMouseEvent(&tme);// 开启 Windows 的 WM_MOUSELEAVE , WM_MOUSEHOVER 事件支持 m_bMouseTracking = true;//为true表示已经开启追踪,false表示现在未跟踪}
}

(3)WM_MOUSEHOVE、WM_MOUSELEAVE中的处理

   case WM_MOUSEHOVER:{m_bMouseTracking=false;}return true;case WM_MOUSELEAVE:{if( m_bMouseTracking ) ::SendMessage(m_hWnd, WM_MOUSEMOVE, 0, (LPARAM) -1);m_bMouseTracking = false;}break;

二、WIN32 ToolTip创建

上面我们完成了对WM_MOUSEHOVER和WM_MOUSELEAVE的追踪,但我们没有做任何的实际工作,我们使用_TrackMouseEvent只是开启了对这两个消息的接收,在接收到消息后,并没有做什么,下面我们就在接收到WM_MOUSEHOVER悬停消息后,创建ToolTip(提示文字)

(1)创建两个变量

 HWND m_hwndTooltip;//TOOLTIP的句柄TOOLINFO m_ToolTip;

讲解:
m_hwndTooltip:保存创建的tooltip窗体的句柄;
m_ToolTip:保存tooltip窗体的创建信息;

(2)创建显示

在需要创建显示TOOLTIP的地方,按照下面的代码,创建就会直接显示出来;

        // Create tooltip informationCStdString sToolTip = L"HAHA HERE   XXXXXXXXXXXX\nXXXXXXXXXXXXXXXXXXXXXXXX\nXXXXXXXXXXXXXXXXXX\nXXXXXXXXXXXXXXXXXXXXXXX";if( sToolTip.IsEmpty() ) return true;::ZeroMemory(&m_ToolTip, sizeof(TOOLINFO));//m_ToolTip.cbSize = sizeof(TOOLINFO);m_ToolTip.cbSize=TTTOOLINFOA_V2_SIZE;m_ToolTip.uFlags = TTF_IDISHWND | TTF_SUBCLASS;m_ToolTip.hwnd = m_hWnd;m_ToolTip.uId = (UINT_PTR) m_hWnd;m_ToolTip.hinst = m_hInstance;m_ToolTip.lpszText = const_cast<LPTSTR>( (LPCTSTR) sToolTip );m_ToolTip.rect =pHover->GetPos();//不用指定显示位置,系统会自动判断位置if( m_hwndTooltip == NULL ) {m_hwndTooltip = ::CreateWindowEx(0, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP | TTS_BALLOON, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, m_hWnd, NULL, m_hInstance, NULL);::SendMessage(m_hwndTooltip, TTM_ADDTOOL, 0, (LPARAM) &m_ToolTip);::SendMessage(m_hwndTooltip, TTM_SETMAXTIPWIDTH, 0, 20); //要多行显示,要先加上这个,然后在要分段的地方加上\n}::SendMessage(m_hwndTooltip, TTM_TRACKACTIVATE, TRUE, (LPARAM) &m_ToolTip);

讲解:
1、创建步骤:
首先填充TOOLINFO结构体;在填充时,m_ToolTip.rect是不必填充的,系统会自动根据当前的鼠标位置显示TOOLTIP;
                          然后SendMessage---TTM_ADDTOOL,增加TOOLTIP到系统中,也就是让系统创建TOOLTIP窗体;
                          最后SendMessage---TTM_TRACKACTIVE,激活当前的TOOLTIP,也就是让其显示出来

2、m_ToolTip.cbSize的填充必须注意!!!!----直接影响到会不会显示出来,这部分会引用另一篇文章在下面讲解(参见:四、参考 ---2);
有些同鞋,根据上面的创建步骤死活就是显示不出来,为什么呢!!!!!m_ToolTip.cbSize赋值时出错了!!!!
如果#define _WIN32_WINNT 0x0500,赋值方式必须是:

m_ToolTip.cbSize = sizeof(TOOLINFO)

而如果_WIN32_WINNT >= 0x0501,对应的赋值方式必须是:

m_ToolTip.cbSize=TTTOOLINFOA_V2_SIZE;

3、多行显示
多行显示必须有两个步骤才能完成:
(1)在显示的字符串中,将要分段的地方用“\n”分隔;
(2)添加代码:

::SendMessage(m_hwndTooltip, TTM_SETMAXTIPWIDTH, 0, 20); //要多行显示,要先加上这个,然后在要分段的地方加上\n

(3)撤销显示

在需要撤销显示的位置,添加上下面这行代码,取消TOOLTIP的激活状态

if( m_hwndTooltip != NULL ) ::SendMessage(m_hwndTooltip, TTM_TRACKACTIVATE, FALSE, (LPARAM) &m_ToolTip);

三、源码讲解(最后有源码下载)

我们在《WIN32界面开发之四:CPaintManagerUI类构建》的基础上进行修改,利用这些教程逐步逼近DUILIB,争取把DUILIB一步步实现,如果对上篇还不了解的同学,还是先看看DUIRudiment是怎么构架的吧。突然到一节来估计是看不懂的。按照上面的内容,大家也应该知道,我们这里要添加的功能就是添加_TrackMouseEvent和TOOLTIP

(1)、修改CPaintManagerUI

1、为CPaintManagerUI添加m_hInstance变量;
大家从TOOLTIP的创建也可以知道,创建ToolTip是要当前应用程序的hInstance的,所以我们要先保存起来,与DUILIB一致,添加静态变量:

static HINSTANCE m_hInstance;//注意在类外初始化

和一个设置函数:

static void SetInstance(HINSTANCE hInst);

设置函数的实现:

void CPaintManagerUI::SetInstance(HINSTANCE hInst)
{m_hInstance = hInst;
}

2、初始化m_hInstance
在WinMain()函数的开头,调用CPaintManagerUI::SetInstance()

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd){Gdiplus::GdiplusStartupInput gdiplusStartupInput;Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);CPaintManagerUI::SetInstance(hInstance);CStartPage *startPage=new CStartPage();startPage->SetInstance(hInstance);startPage->Create();startPage->ShowWindow(true);Message();delete startPage;Gdiplus::GdiplusShutdown(gdiplusToken);return 0;
}

(2)TOOLTIP创建

在WM_MOUSEHOVER中创建TOOLTIP,先看代码:

   case WM_MOUSEHOVER:{m_bMouseTracking = false;POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };CControlUI* pHover =m_pRoot->FindCtrlFromPT(pt);if( pHover == NULL ) break;// Generate mouse hover eventif( m_pEventHover != NULL ) {TEventUI event = { 0 };event.ptMouse = pt;event.Type = UIEVENT_MOUSEHOVER;event.pSender = m_pEventHover;event.dwTimestamp = ::GetTickCount();m_pEventHover->Event(event);}//这段与创建TOOLTIP无关,这里是给控件发送HOVER事件// Create tooltip informationCStdString sToolTip = L"HAHA HERE   XXXXXXXXXXXX\nXXXXXXXXXXXXXXXXXXXXXXXX\nXXXXXXXXXXXXXXXXXX\nXXXXXXXXXXXXXXXXXXXXXXX";if( sToolTip.IsEmpty() ) return true;::ZeroMemory(&m_ToolTip, sizeof(TOOLINFO));//m_ToolTip.cbSize = sizeof(TOOLINFO);m_ToolTip.cbSize=TTTOOLINFOA_V2_SIZE;m_ToolTip.uFlags = TTF_IDISHWND | TTF_SUBCLASS;m_ToolTip.hwnd = m_hWnd;m_ToolTip.uId = (UINT_PTR) m_hWnd;m_ToolTip.hinst =m_hInstance;m_ToolTip.lpszText = const_cast<LPTSTR>( (LPCTSTR) sToolTip );m_ToolTip.rect =pHover->GetPos();//不用指定显示位置,系统会自动判断位置if( m_hwndTooltip == NULL ) {m_hwndTooltip = ::CreateWindowEx(0, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP | TTS_BALLOON, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, m_hWnd, NULL,m_hInstance, NULL);::SendMessage(m_hwndTooltip, TTM_ADDTOOL, 0, (LPARAM) &m_ToolTip);::SendMessage(m_hwndTooltip, TTM_SETMAXTIPWIDTH, 0, 20); //要多行显示,要先加上这个,然后在要分段的地方加上\n}::SendMessage(m_hwndTooltip, TTM_TRACKACTIVATE, TRUE, (LPARAM) &m_ToolTip);}return true;

讲解:
1、在WM_MOUSEHOVER消息中,我们先给当前控件发送MOUSEHOVER事件
2、创建并显示TOOLTIP,由于在我的targetver.h 文件中定义的_WIN32_WINNT是0x0600;所以我这里的赋值方式为:m_ToolTip.cbSize=TTTOOLINFOA_V2_SIZE;

#ifndef _WIN32_WINNT            // 指定要求的最低平台是 Windows Vista。
#define _WIN32_WINNT 0x0600     // 将此值更改为相应的值,以适用于 Windows 的其他版本。
#endif

(3)移出时撤销显示

这里有两个地方要撤销显示,首先当鼠标移出控件时,要撤销显示,再者,在移出当前窗体时,也要撤销显示;
1、鼠标移出控件时的代码:
在WM_MOUSEMOVE中,在移出控件时,添加SendMessage---TTM_TRACKACTIVATE , FALSE

        if( pNewHover != m_pEventHover && m_pEventHover != NULL ) {event.Type = UIEVENT_MOUSELEAVE;event.pSender = m_pEventHover;m_pEventHover->Event(event);//在鼠标离开控件时,要取消激活TOOLTIP,也就是让其不显示!if( m_hwndTooltip != NULL ) ::SendMessage(m_hwndTooltip, TTM_TRACKACTIVATE, FALSE, (LPARAM) &m_ToolTip);m_pEventHover = NULL;}

2、鼠标移出窗体时

由于我们用_TrackMouseEvent监听的HWND是窗体的HWND,所以鼠标在移出窗体时,会触发WM_MOUSELEAVE消息;所以在WM_MOUSELEAVE同样添加撤销代码:

   case WM_MOUSELEAVE:{if( m_hwndTooltip != NULL ) ::SendMessage(m_hwndTooltip, TTM_TRACKACTIVATE, FALSE, (LPARAM) &m_ToolTip);if( m_bMouseTracking ) ::SendMessage(m_hWnd, WM_MOUSEMOVE, 0, (LPARAM) -1);m_bMouseTracking = false;}

四、参考

1、MSDN关于TOOLLIP的各项参数及用法讲解:http://msdn.microsoft.com/en-us/library/windows/desktop/bb760246%28v=vs.85%29.aspx

2、《 不靠谱的tooltip》,讲解了_WIN32_WINNT值与tooltip.cbSize的关系;这也就是大部分创建不成功的原因所在;网址: http://blog.csdn.net/problc/article/details/6654601

《不靠谱的tooltip》摘录

typedef struct tagTOOLINFOA {
UINT cbSize;
UINT uFlags;
HWND hwnd;
UINT_PTR uId;
RECT rect;
HINSTANCE hinst;
LPSTR lpszText;
#if (_WIN32_IE >= 0x0300)
LPARAM lParam;
#endif
#if (_WIN32_WINNT >= 0x0501)
    void *lpReserved;
#endif
} TTTOOLINFOA, NEAR *PTOOLINFOA, *LPTTTOOLINFOA;
如果#define _WIN32_WINNT 0x0500,那么tooltip一切正常
当有一天#define _WIN32_WINNT 0x0501了,
这时设置tooltip.cbSize = sizeof(TOOLINFO)的时候就让人崩溃了。
编译调试不显示任何错误,但是tooltip就是显示不出来了。。。(they were just failing silently without knowing why)
因为系统默认加载comctl 5.82,这个版本里面的tooltip的size根本没有sizeof(TOOLINFO),里面没有void *lpReserved;
所以cbSize设大了,出错了。。。
这时需要写成 tooltip.cbSize = TTTOOLINFOA_V2_SIZE;
或者强制指定comctl 6.0
#pragma comment(linker, "\"/manifestdependency:type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df' language='*'\"")
ps:  指定#define _WIN32_WINNT 0x0501将导致程序只能运行在xp及以上系统。

五、最后

本文由HARVIC完成,如若转载,请标明出处,请大家尊重初创者的版权,谢谢!!

源文地址:http://blog.csdn.net/harvic880925/article/details/9796229

源码地址:http://download.csdn.net/detail/harvic880925/5881347

声明:感谢金山影音漂亮的界面图片,该图片来自网络。

_TrackMouseEvent 与 WIN32 ToolTip相关推荐

  1. VC++ ToolTip的简单使用

    1.在基于对话框的MFC应用程序中使用Tooltip,首先在Dlg类的头文件中定义一个变量: CToolTipCtrl m_iToolTips; 2.在Dlg类的OnInitDialog中添加代码: ...

  2. Win32消息集合----方便查阅

    // #include "AFXPRIV.H"//消息值的定义来源 #include "Dde.h"//DDE消息值的定义来源 #include "C ...

  3. win32汇编学习的一些摘要

    sizeof 变量名,数据类型或数据结构 lengthof 变量名.数据类型或数据结构名 sizeof 伪指令可以取得变量.数据类型或数据结构以字节为单位的长度,lengthof可以取得变量中数据的项 ...

  4. [WTL/ATL]_[初级]_[TreeView控件如何显示ToolTip]

    场景 在开发界面程序时,CTreeViewCtrl(它实际内部封装的就是Win32的TreeView控件)一般会用来作为选择某些类型的树形菜单,点击某项的时候,右边能显示某些对应的数据.当这个控件的宽 ...

  5. 【WIN32之旅】给托盘图标加上MOUSE_ENTER、MOUSE_HOVER、MOUSE_LEAVE消息

    转载请说明原出处,谢谢~ http://blog.csdn.net/seven_1992/article/details/50848071 相信很多人在WIN32项目开发过程中涉及到托盘相关处理时都会 ...

  6. [ATL/WTL]_[初级]_[窗口如何实现一个Tooltip]

    场景: 1.  WTL的控件默认不支持进入和移出的 WM_MOUSEHOVER ,WM_MOUSELEAVE 事件, 即使写了映射也没用, 必须要使用函数 _TrackMouseEvent  添加监听 ...

  7. 小D学blend-----如何创建自定义的Tooltip控件

    运行环境:blend 4.0或者blend 3.0 +silverlight 3.0(其实我相信步骤应该是差不多的) 语言:C# Tooltip类:它是表示一个长方形的小弹出窗口,该窗口在用户将指针悬 ...

  8. 设置echarts的grid、tooltip、柱状图渐变色、折线图渐变色

    grid: {show: false,left: '0px',top: '50px',right: '1px',bottom: '0px',containLabel: true,backgroundC ...

  9. Don’t Use the Win32 API PostThreadMessage() to Post Messages to UI Threads(翻译)

    大龙的博客 C++博客 | 首页 | 发新随笔 | 发新文章 | 联系 | 聚合 | 管理 Don't Use the Win32 API PostThreadMessage() to Post Me ...

最新文章

  1. java 实体类包含list 怎么取值_2019 最新 500 道 Java 面试题
  2. EDIUS输出到文件
  3. elasticsearch组件的安装启动,测试等(windows)
  4. c语言实现堆Stack(附完整源码)
  5. Pandas GroupBy 分组(分割-应用-组合)
  6. 新书正式定名《互联网运营智慧》
  7. 用户故事 | 刷算法面试题的4种思考方式
  8. Golang解析yaml格式文件
  9. 一三五、服务器部署Node项目、Vue spa静态项目、ssr项目
  10. 人脸识别:AI产品经理需要了解的CV通识
  11. AI人机对战五子棋游戏【Python(pygame)+AI】并实现软件输出
  12. JAVA能写大型游戏么?
  13. Linux对文本查找、检索、统计及替换的常用命令
  14. redis如何查看主从状态信息master和salve
  15. C# 模拟PCM数据并创建WAV文件
  16. 什么是模式识别,对抗学习是什么?
  17. Maxscript基本数据类型(二):Name
  18. Lect1 String相关题目
  19. 【AI书籍】未来哪些职业会被人工智能所替代,听李开复老师怎么说
  20. linux安装——管理应用程序

热门文章

  1. 如何设计一个完整的共享充电宝系统?
  2. linux欧拉强制修改root密码,openEuler 20.03 LTS安装图文教程
  3. immutable java_Java多线程基础(四)——Immutable模式
  4. TP框架如何开启log日志
  5. List集合的复制方式
  6. 【图像】【OpenGL】VAO和VBO的关系
  7. Android手机应用开发(八) | 制作简单音乐播放器
  8. 数据库函数依赖名词的解释
  9. H264 的视频编码层的错误恢复
  10. [英语阅读]印度生物识别考勤 促办公效率