ToolTip一般用法和高级用法_ontoolhittest_liubin15989534919的博客-程序员秘密

技术标签: string  null  ttf  mfc  框架  class  

ToolTip是Win32中一个通用控件,MFC中为其生成了一个类CToolTipCtrl,总的说来其使用方法是较简单的,下面讲一下它的一般用法和高级用法。   
    
  一般用法步骤:   
    
  添加CToolTipCtrl成员变量   m_tt。   
    
  在父窗口中调用EnableToolTips(TRUE);   
    
  在窗口的OnCreate(或者其他适当的位置)中向ToolTip中添加需要显示Tip的子窗口,并同时指定相应的显示字串CToolTipCtrl::AddTool(pWnd,"string   to   display")。   
    
  重载父窗口的   BOOL   PreTranslateMessage(MSG*   pMsg)   ,在函数中调用   m_tt.RelayEvent(pMsg)。   
    
  下面假设在窗口CWndYour中使用CToolTipCtrl   
    
  在类定义中添加变量说明:   
  class   CWndYour:xxx   
  {   
  CToolTipCtrl   m_tt;   
  }   
  在OnCreate中添加需要显示Tip的子窗口   
  CWndYour::OnCreate(....)   
  {   
  EnableToolTips(TRUE);   
  m_tt.Create(this);   
  m_tt.Activate(TRUE);   
    
  CWnd*   pW=GetDlgItem(IDC_CHECK1);//得到窗口指针   
  m_tooltip.AddTool(pW,"Check1");//添加   
  ........   
  }   
  在BOOL   PreTranslateMessage(MSG*   pMsg)中添加代码   
  BOOL   CWndYour::PreTranslateMessage(MSG*   pMsg)   
  {   
  {   
  m_tt.RelayEvent(pMsg);   
  }   
  return   CParentClass::PreTranslateMessage(pMsg);   
  }   
    
  这样当鼠标移动到相应的子窗口上时会显示出相应的ToolTip。   
    
  动态改变ToolTip的显示内容的方法及步骤:   
    
  上面所讲的1、2、4步骤。   
    
  在增加ToolTip时不指定显示的字串,而是使用LPSTR_TEXTCALLBACK。   
    
  在窗口中增加消息映射   ON_NOTIFY_EX(   TTN_NEEDTEXT,   0,   SetTipText   )。   
    
  在窗口中增加一个函数用于动态提供显示内容,其原型为   BOOL   SetTipText(   UINT   id,   NMHDR   *   pTTTStruct,   LRESULT   *   pResult   ),下面的代码可以根据传入的参数判定应该显示的内容。   
    
  BOOL   CWndYour::SetTipText(   UINT   id,   NMHDR   *   pTTTStruct,   LRESULT   *   pResult   )   
  {   
  TOOLTIPTEXT   *pTTT   =   (TOOLTIPTEXT   *)pTTTStruct;           
  UINT   nID   =pTTTStruct->idFrom;   //得到相应窗口ID,有可能是HWND   
  if   (pTTT->uFlags   &   TTF_IDISHWND)         //表明nID是否为HWND   
  {   
                  nID   =   ::GetDlgCtrlID((HWND)nID);//从HWND得到ID值,当然你也可以通过HWND值来判断   
  switch(nID)   
  case(IDC_YOUR_CONTROL1)                   
  strcpy(pTTT->lpszText,your_string1);//设置   
  return   TRUE;   
  break;   
  case(IDC_YOUR_CONTROL2)   
  //设置相应的显示字串   
  return   TRUE;   
  break;   
  }   
  return(FALSE);   
  }



我用VC做TOOL TIP很多次了,但每次都要再研究一遍.虽然说学而时习,应该的,但主要还是由于自己懒.今天一定要记下来.以后再用的时候,就是参考.也请阅读此文的朋友记下来,将来查阅用.

用VC实现TOOL TIP.比较复杂,其实也简单,但MFC帮助一些窗口实现,而另一些窗口又不实现,倒搞得复杂了.最开始我用WM_MOUSEMOVE消息,然后用CToolTipCtrl::Pop,这个方法太笨.不建议用.除非需要自定义.

MFC对TOOL TIP的支持不错的.缺省情况CFrameWnd支持很好.然后是CWnd.主要体现在TTN_NEEDTEXT消息的支持和OnToolHitTest的支持.TTN_NEEDTEXT是在CFrameWnd中支持的.OnToolHitTest是在CWnd中支持的.有了这些支持,可以在框架窗口中很好实现ToolBar的TIP.和在一个对话框中很好实现一个控件的TOOL TIP.

举例.在对话框中实现TOOL TIP.

1.EnableToolTips( TRUE )是不可少的.建议在:CDialog::OnInitDialog 调用吧.

2.ON_NOTIFY_EX( TTN_NEEDTEXT, 0, OnNeedText ).OnNeedText实现了TOOL TIP的文字.传入的参数idFrom是控件的ID,根据控件ID得到相应的TIP文字

就这么简单的两步,就实现了对话框中的TOOL TIP.其实不只对话框,任何窗口都可以用上面的方法实现自己的子窗口控件的TIP.但前提是必须是CWnd的派生类.

这就看出了MFC对TOOL TIP的支持很厉害

但这一切都是MFC实现的我们简单描述一下它的实现原理,这样看得更清楚

CWnd本身就带有一个CToolTipCtrl对象,是放在pThreadState中的这个不说了,知道CWnd有就行了

CWnd负责创建它,然后在PreTranslateMessage中调用了FilterToolTipMessage,这个函数的作用是处理WM_MOUSEMOVE,WM_NCMOUSEMOVE等消息,给CToolTipCtrl一个机会,判断鼠标是否在需要显示TIP的窗口上,如果是,就显示.FilterToolTipMessage先从CWnd::OnToolHitTest得到TOOLINFO:中的数据,比如哪个控件需要TIP等信息,然后利用ADDTOOL消息把这个需要TIP的控制加入到CToolTipCtrl的TOOL列表中,然后将鼠标移动的消息转给CToolTipCtrl处理.如果这个TIP的文字需要用回调函数来获得,就用WM_NOTIFY的TTN_NEEDTEXT从CToolTipCtrl的父窗口获取.这个过程就是CToolTipCtrl判断是否要显示TIP,到获得文字并显示TIP的全过程

这样一分析,就知道原来CWnd帮助实现了控件子窗口的TIP其实就是实现了OnToolHitTest这个函数,然后在PreTranslateMessage中转发消息,帮助CToolTipCtrl正确显示TIP.

而CFrameWnd是实现了TTN_NEEDTEXT的响应,帮助子窗口实现TIP.

其实我们也可以不要这些缺省实现,自己用CToolTipCtrl搞定,做法一样:

1.CToolTipCtrl::Create创建Tool Tip

2.AddTool增加一个TOOL,这里的TOOL就是需要显示TIP的一个区域或一个子窗口.如果对AddTool使用有不清楚的地方,建议查看源程序.可能会觉得直接使用TTM_ADDTOOL更方便.

3.在PreTranslateMessage中调用CToolTipCtrl::RelayMessage

4.如果在AddTool中,文字是用回调函数实现,那就要处理TTN_NEEDTEXT消息.

其实自己创建CToolTipCtrl和MFC做的一样.只是不需要在OnToolHitTest中给出需要显示TIP的窗口或者区域.

如果给子窗口用TIP.就用MFC最简单.如果给自己呢?

设置TOOLINFO中的uFlags = TTF_IDISHWND,然后设置uId为窗口句柄,hWnd为窗口句柄就可以了.

写了这么多,有不对的地方还请和我联系一下,帮助我改正错误.

只是有个问题还没搞明白.就是为什么MFC把CToolTipCtrl放在了pThreadState中.难道是为了用一个TOOL TIP为该线程的所有窗口服务吗?难道是一种节约资源的表现.这点还需要研究.如果哪位朋友知道答案,还希望能不吝赐教.谢谢.



用VC实现TOOL TIP2008-03-17 13:57按照下面的步骤去做:
1、先为static设置一个ID,如ID_TIP;
2、在CDialogBar的头文件中的AFX_MSG内加入一行申明
afx_msg BOOL OnToolTip(UINT id,NMHDR * pNMHDR,LRESULT * pResult);
3、在CDialogBar的CPP文件中的AFX_MSG_MAP内加入一行
ON_NOTIFY_EX(TTN_NEEDTEXT,0,OnToolTip)
4、在CDialogBar的CPP文件中的OnInitDialog()函数内加入
EnableToolTips(TRUE);
5、在CDialogBar的CPP文件中添加OnToolTip函数
BOOL CDialogBar::OnToolTip(UINT id,NMHDR * pNMHDR,LRESULT * pResult)
{
TOOLTIPTEXT * pTTT=(TOOLTIPTEXT *)pNMHDR;
UINT uID = pNMHDR->idFrom;
if(pTTT->uFlags & TTF_IDISHWND)
uID = ::GetDlgCtrlID((HWND)uID);
if(uID == NULL) return FALSE;
switch(uID)
{
case IDC_TIP:
pTTT->lpszText="添加你的提示内容";
break;
}
return TRUE;
}
这样就可以了。
其实,上面的方法可以为任何控件添加tip提示。


用VC实现TOOL TIP.比较复杂,其实也简单,但MFC帮助一些窗口实现,而另一些窗口又不实现,倒搞得复杂了.最开始我用WM_MOUSEMOVE消息,然后用CToolTipCtrl::Pop,这个方法太笨.不建议用.除非需要自定义.

MFC对TOOL TIP的支持不错的.缺省情况CFrameWnd支持很好.然后是CWnd.主要体现在TTN_NEEDTEXT消息的支持和OnToolHitTest的支持.TTN_NEEDTEXT是在CFrameWnd中支持的.OnToolHitTest是在CWnd中支持的.有了这些支持,可以在框架窗口中很好实现ToolBar的TIP.和在一个对话框中很好实现一个控件的TOOL TIP.

举例.在对话框中实现TOOL TIP.

1.EnableToolTips( TRUE )是不可少的.建议在:CDialog::OnInitDialog 调用吧.

2.ON_NOTIFY_EX( TTN_NEEDTEXT, 0, OnNeedText ).OnNeedText实现了TOOL TIP的文字.传入的参数idFrom是控件的ID,根据控件ID得到相应的TIP文字

就这么简单的两步,就实现了对话框中的TOOL TIP.其实不只对话框,任何窗口都可以用上面的方法实现自己的子窗口控件的TIP.但前提是必须是CWnd的派生类.

这就看出了MFC对TOOL TIP的支持很厉害

但这一切都是MFC实现的我们简单描述一下它的实现原理,这样看得更清楚

CWnd本身就带有一个CToolTipCtrl对象,是放在pThreadState中的这个不说了,知道CWnd有就行了

CWnd负责创建它,然后在PreTranslateMessage中调用了FilterToolTipMessage,这个函数的作用是处理WM_MOUSEMOVE,WM_NCMOUSEMOVE等消息,给CToolTipCtrl一个机会,判断鼠标是否在需要显示TIP的窗口上,如果是,就显示.FilterToolTipMessage先从CWnd::OnToolHitTest得到TOOLINFO:中的数据,比如哪个控件需要TIP等信息,然后利用ADDTOOL消息把这个需要TIP的控制加入到CToolTipCtrl的TOOL列表中,然后将鼠标移动的消息转给CToolTipCtrl处理.如果这个TIP的文字需要用回调函数来获得,就用WM_NOTIFY的TTN_NEEDTEXT从CToolTipCtrl的父窗口获取.这个过程就是CToolTipCtrl判断是否要显示TIP,到获得文字并显示TIP的全过程

这样一分析,就知道原来CWnd帮助实现了控件子窗口的TIP其实就是实现了OnToolHitTest这个函数,然后在PreTranslateMessage中转发消息,帮助CToolTipCtrl正确显示TIP.

而CFrameWnd是实现了TTN_NEEDTEXT的响应,帮助子窗口实现TIP.

其实我们也可以不要这些缺省实现,自己用CToolTipCtrl搞定,做法一样:

1.CToolTipCtrl::Create创建Tool Tip

2.AddTool增加一个TOOL,这里的TOOL就是需要显示TIP的一个区域或一个子窗口.如果对AddTool使用有不清楚的地方,建议查看源程序.可能会觉得直接使用TTM_ADDTOOL更方便.

3.在PreTranslateMessage中调用CToolTipCtrl::RelayMessage

4.如果在AddTool中,文字是用回调函数实现,那就要处理TTN_NEEDTEXT消息.

其实自己创建CToolTipCtrl和MFC做的一样.只是不需要在OnToolHitTest中给出需要显示TIP的窗口或者区域.

如果给子窗口用TIP.就用MFC最简单.如果给自己呢?

设置TOOLINFO中的uFlags = TTF_IDISHWND,然后设置uId为窗口句柄,hWnd为窗口句柄就可以了.

写了这么多,有不对的地方还请和我联系一下,帮助我改正错误.

只是有个问题还没搞明白.就是为什么MFC把CToolTipCtrl放在了pThreadState中.难道是为了用一个TOOL TIP为该线程的所有窗口服务吗?难道是一种节约资源的表现.这点还需要研究.如果哪位朋友知道答案,还希望能不吝赐教.谢谢


//头文件加入
CToolTipCtrl m_tooltip;
//主窗口初始化时加入
m_tooltip.Create(this);
m_tooltip.Activate(TRUE);
m_tooltip.AddTool(GetDlgItem(IDC_>name<), ">text<");
//IDC_>name<为你控件的ID,>text<为显示的内容

利用ClassWizard建立PreTranslateMessage
BOOL CTest5Dlg::PreTranslateMessage(MSG* pMsg)
{
m_tooltip.RelayEvent(pMsg); //你加入的代码
return CDialog::PreTranslateMessage(pMsg);
}


如何用VC++实现在对话框的控件上显示ToolTip 并在状态条上显示控件的信息
湖南省邮电五二六厂
肖天鹏
---- 利用 VC++ 的 AppWizard,可以很容易地实现工具条和菜单项的 ToolTip 或在状态条上显 示帮助信息,但要在对话框的控件上显示 ToolTip 并在状态条上显示控件信息并不是那么容易, 其实,利用 VC++ 中的 WM_SETCURSOR 与 TTN_NEEDTEXT 消息就可达到目的。具体操作如下:

---- 一

---- 利用 VC++ 的 MFC AppWizard 生成一个 SDI 或 MDI 的应用程序

---- 二

---- 编辑对话框控件的字符串资源

---- 例如:

---- IDC_DBBUTTON1 = "this is 肖天鹏的第一自制按钮\n天 鹏", 其中字符串"this is 肖天鹏的第一自制按钮"将在鼠标移到控件上时显示在状态条上,字符串"天 鹏"将作为 ToolTip 显示。

---- 三

---- 建立消息映射。

---- 在对话框的头文件 (*.H) 中加入以下代码:

protected:
    void SetStatusText(UINT nID=0);
    //{ {AFX_MSG(CFileOp1)
    afx_msg void OnDestroy();
    afx_msg BOOL OnSetCursor(CWnd* pWnd,
    UINT nHitTest, UINT message);
    //}}AFX_MSG
    afx_msg BOOL OnTipNotify( UINT id, NMHDR *
     pNMHDR, LRESULT * pResult );
    DECLARE_MESSAGE_MAP()
---- 在对话框的实现文件 (*.CPP) 中加入以下代码:

BEGIN_MESSAGE_MAP(CFileOp1, CDialog)
    //{ {AFX_MSG_MAP(CFileOp1)
    ON_WM_DESTROY()
    ON_WM_SETCURSOR()
    //}}AFX_MSG_MAP
    ON_NOTIFY_EX(TTN_NEEDTEXT,0,OnTipNotify)
END_MESSAGE_MAP()
---- 四

---- 编辑消息处理函数。

BOOL CFileOp1::OnSetCursor
(CWnd* pWnd, UINT nHitTest, UINT message)
{
// TODO: Add your message handler
 code here and/or call default
    if(pWnd==this)
        SetStatusText();
    else
    {
        TOOLTIPTEXT m_psttt;
        m_psttt.hdr.hwndFrom=m_hWnd;
        m_psttt.hdr.idFrom=pWnd- >GetDlgCtrlID();
        m_psttt.hdr.code=TTN_NEEDTEXT;
        m_psttt.uFlags= TTF_IDISHWND;
        SetStatusText(pWnd- >GetDlgCtrlID());
        this- >SendMessage(WM_NOTIFY,
        m_psttt.hdr.idFrom,(LPARAM)&m_psttt);
    }
return CDialog::OnSetCursor
 (pWnd, nHitTest, message);
}

void CFileOp1::OnDestroy()
{
    SetStatusText();
    CDialog::OnDestroy();
}

void CFileOp1::SetStatusText(UINT nID)
{
    if(nID==0)
        nID=AFX_IDS_IDLEMESSAGE;
    CWnd *pWnd=AfxGetMainWnd()- >GetDescendantWindow
    (AFX_IDW_STATUS_BAR);
    if(pWnd)
    {
        AfxGetMainWnd()- >SendMessage
        (WM_SETMESSAGESTRING ,nID);
        pWnd- >SendMessage(WM_IDLEUPDATECMDUI);
        pWnd- >UpdateWindow();
    }
}

BOOL CFileOp1::OnTipNotify( UINT id, NMHDR *
 pNMHDR, LRESULT * pResult )
{
    TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
    UINT nID =pNMHDR- >idFrom;
    if (pTTT- >uFlags & TTF_IDISHWND)
    {
        nID = ::GetDlgCtrlID((HWND)nID);
        if(nID)
        {
        TCHAR szFullText[256];
        CString StrTipText;
        AfxLoadString(nID,szFullText);
        AfxExtractSubString(StrTipText,
        szFullText,1,'\n');
        if(!StrTipText.IsEmpty())
            strcpy(pTTT-  >lpszText,StrTipText);
            pTTT-  >hinst = AfxGetResourceHandle();
            return(TRUE);
        }
    }
    return(FALSE);
}
---- 五

---- 在 Stdafx.h 文件中加入以下指令:

    #include 〈 afxpriv.h>
    #include 〈 afxres.h>
---- 六

---- 将该对话框作为一个 SDI 或 MDI 应用程序的主框架的子窗口,生成这样一个对话框后,当你把鼠标移到某个控件 ( 必须有相应的字符串资源 )上时,就会出现该控件的 ToolTip 和状态条信息。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/liubin15989534919/article/details/6837093

智能推荐

vuex中store.commit和store.dispatch的区别及用法_await store.dispatch_longzhoufeng的博客-程序员秘密

代码示例:this.$store.commit('loginStatus', 1);this.$store.dispatch('isLogin', true);规范的使用方式:// 以载荷形式store.commit('increment',{ amount: 10 //这是额外的参数})// 或者使用对象风格的提交方式store.commit({ type: ...

(Unsupervised Anomaly Detection)无监督异常检测领域最新研究进展 - Part 1 基于重构的方法(1) 【持续更新...】_基于重构的异常检测_我是大黄同学呀的博客-程序员秘密

文章目录前言1. 基线 AE/VAE2. 基于inpainting思想2.1 SMAI (BMVC2020)2.2 SCADN (AAAI2021)2.3 RIAD (PR2021)3. 基于Memory Bank3.1前言在图像异常检测中,基于重构的方法是一种很自然的思想:构建一个Encoder-Decdoer结构的网络执行重构任务,目标是让模型能够重构好正常样本。那么在测试时,对于正常样本仍然能够正常重构,而异常样本由于分布的差异,导致重构效果较差,从而可以通过像素级的比较得到异常得分,判断一个样本

localStorage数据缓存_localstorge會自動存儲數據嗎_「已注销」的博客-程序员秘密

Window localStorage数据缓存localStorage 的作用localStorage 和 sessionStorage 属性允许在浏览器中存储 key/value 对的数据。localStorage 用于长久保存整个网站的数据,保存的数据没有过期时间,直到手动去删除。localStorage 属性是只读的。提示: 如果你只想将数据保存在当前会话中,可以使用 sessionStorage 属性, 该数据对象临时保存同一窗口(或标签页)的数据,在关闭窗口或标签页之后将会删除这些数据。

托管服务器ip绑定域名_无限的免费托管和域名_weixin_26705651的博客-程序员秘密

托管服务器ip绑定域名Having a web profile is cool, right? It stays online for anyone to see and sharing it with anyone is just so easy. You can share your work or portfolio in just one web address. 拥有个人资料很酷,对吧?...

【图像压缩】基于行程编码实现图像压缩附matlab代码_行程编码压缩_Matlab科研工作室的博客-程序员秘密

1 简介编码是方法建立在图像统计特性的基础上的。例如,在传真通信中的文件大多是二值图像,即每个像素的灰度值只有0和1两种取值。将一行中颜色值相同的相邻象素用一个计数值和该颜色值来代替。例如aaabccccccddeee可以表示为3a1b6c2d3e,,即有3个a,1个b,6个c,2个d,3个e。如果一幅图象是由很多块颜色相同的大面积区域组成,那么采用行程编码的压缩效率是惊人的。然而,该算法也导致了一个致命弱点,如果图象中每两个相邻点的颜色都不同,用这种算法不但不能压缩,反而数据量增加一倍。因此对有大面.

神级程序猿用HTML5代码画出恐龙求欢图,想象力太丰富!_weixin_34072637的博客-程序员秘密

点击查看恐龙的爱恋特效纯HTML5/CSS3画出唯美恐龙之爱,无javascript!最近都比较偏向于找纯CSS3动画,或者游戏特效,前段时间写了太多的javascript的特效,案例,包括封装插件,ajax,javascript设计模式等等这方面的,换了风格,高点小清新的,唯美动画给大家分享。现在很多地方都应用到了HTML5的知识,国外现在也很流行HTML5网站,在国内的话应用的比较广的应该是移...

随便推点

Ext 4.2 的工具栏_ext只有刷新的工具栏_沙子揉碎在眼睛里的博客-程序员秘密

面板中可以有工具栏,工具栏可以位于面板顶部或底部,Ext 中工具栏是由Ext.Toolbar类表示。工具栏上可以存放按钮、文本、分隔符等内容。面板对象中内置了很多实用的工具栏,可以直接通过面板的tools 配置选项往面板头部加入预定义的工具栏选项。比如下面的代码:&amp;lt;script type=&quot;text/javascript&quot;&amp;gt;    &amp;lt;!--       Ext.onReady(f...

第七周实验报告(一)_cailwen的博客-程序员秘密

* (程序头部注释开始)* 程序的版权和版本声明部分* Copyright (c) 2011, 烟台大学计算机学院学生* All rights reserved.* 文件名称:写出静态成员的初始化及各成员函数的定义* 作 者:齐艳红 * 完成日期: 2011年 4月 3日*版 本 号: * 对任务及求解方法的描述部分 *问题描述:含有静态数据成员和成员函数的Ti

SimpleDateFormat 格式化日期_Java成长记_Camel的博客-程序员秘密

包含在Java的 java.text.SimpleDateFormat;包中日期和时间格式由 日期和时间模式字符串 指定。在 日期和时间模式字符串 中,未加引号的字母 ‘A’ 到 ‘Z’ 和 ‘a’ 到 ‘z’ 被解释为模式字母,用来表示日期或时间字符串元素。文本可以使用单引号 (’) 引起来,以免进行解释。所有其他字符均不解释;只是在格式化时将它们简单复制到输出字符串白话文的讲:这些A——Z...

Java学习.1_风飚飏的博客-程序员秘密

1、数值录入Scanner sc = new Scanner(System.in);// System.out.println("Piease input x = ");// double x = sc.nextDouble();// System.out.println("Please input y = ");// double y = sc.nextDouble();// System.out.println("Plea

推荐文章

热门文章

相关标签