CToolTip使用&CListCtrl添加多行提示

来源:互联网 发布:深渊巨口皮肤淘宝 编辑:程序博客网 时间:2024/05/29 02:57

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 TRUE;

 

 另外的就是在相应函数中区分UNICODE编码

[cpp] view plaincopyprint?
  1. BOOL CPreParent::OnToolTipText(UINT, NMHDR* pNMHDR, LRESULT* pResult)  
  2. {  
  3.     ASSERT(pNMHDR->code == TTN_NEEDTEXTA || pNMHDR->code == TTN_NEEDTEXTW);  
  4.       
  5.     // UNICODE消息   
  6.     TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;  
  7.     TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;  
  8.     //TCHAR szFullText[512];   
  9.     CString strTipText;  
  10.     UINT nID = pNMHDR->idFrom;  
  11.       
  12.     if (pNMHDR->code == TTN_NEEDTEXTA && (pTTTA->uFlags & TTF_IDISHWND) ||  
  13.         pNMHDR->code == TTN_NEEDTEXTW && (pTTTW->uFlags & TTF_IDISHWND))  
  14.     {  
  15.         // idFrom为工具条的HWND    
  16.         nID = ::GetDlgCtrlID((HWND)nID);  
  17.     }  
  18.       
  19.     if (nID != 0) //不为分隔符  
  20.     {  
  21.         strTipText.LoadString(nID);  
  22.         strTipText = strTipText.Mid(strTipText.Find('\n',0)+1);  
  23.         //strTipText = _T("notify string");  
  24.           
  25. #ifndef _UNICODE   
  26.         if (pNMHDR->code == TTN_NEEDTEXTA)  
  27.         {  
  28.             lstrcpyn(pTTTA->szText, strTipText, sizeof(pTTTA->szText));  
  29.         }  
  30.         else  
  31.         {  
  32.             _mbstowcsz(pTTTW->szText, strTipText, sizeof(pTTTW->szText));  
  33.         }  
  34. #else   
  35.         if (pNMHDR->code == TTN_NEEDTEXTA)  
  36.         {  
  37.             _wcstombsz(pTTTA->szText, strTipText,sizeof(pTTTA->szText));  
  38.         }  
  39.         else  
  40.         {  
  41.             lstrcpyn(pTTTW->szText, strTipText, sizeof(pTTTW->szText));  
  42.         }  
  43. #endif   
  44.           
  45.         *pResult = 0;  
  46.           
  47.         //使工具条提示窗口在最上面   
  48.         ::SetWindowPos(pNMHDR->hwndFrom, HWND_TOP, 0, 0, 0, 0,  
  49.             SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOOWNERZORDER);   
  50.         return TRUE;  
  51.     }  
  52.     return TRUE;  
  53. }  

MFC中CListCtrl添加多行提示信息方法

这里是用一个类CToolTipListCtrl实现,它继承自CListCtrl。添加提示信息的时候只需要在OnToolTipText函数中if( nFlags & LVHT_ONITEMLABEL )代码块中设置你要显示的值给m_strToolTipText就可以了。这个时候你就可以为不同的单元格显示不同的提示信息,而且提示信息可以为任意多行,提示信息可以使用“\n”分行。

 

ToolTipListCtrl.h的代码如下:
#pragma once// CToolTipListCtrlclass CToolTipListCtrl : public CListCtrl{ DECLARE_DYNAMIC(CToolTipListCtrl)public: CToolTipListCtrl(); virtual ~CToolTipListCtrl(); virtual int OnToolHitTest(CPoint point, TOOLINFO * pTI) const;protected: virtual afx_msg BOOL OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT *  pResult ); DECLARE_MESSAGE_MAP()private: CString m_strToolTipText;//Item的提示信息};


 

ToolTipListCtrl.cpp的代码如下:

 
#include "stdafx.h"#include "ListCtrlToolTipTest.h"#include "ToolTipListCtrl.h"// CToolTipListCtrlIMPLEMENT_DYNAMIC(CToolTipListCtrl, CListCtrl)CToolTipListCtrl::CToolTipListCtrl(){}CToolTipListCtrl::~CToolTipListCtrl(){}BEGIN_MESSAGE_MAP(CToolTipListCtrl, CListCtrl) ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText) ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)END_MESSAGE_MAP() // CToolTipListCtrl 消息处理程序int CToolTipListCtrl::OnToolHitTest(CPoint point, TOOLINFO * pTI) const { //See if the point falls onto a list item //UINT nFlags = 0; LVHITTESTINFO lvhitTestInfo; lvhitTestInfo.pt = point; int nItem = ListView_SubItemHitTest(  this->m_hWnd,  &lvhitTestInfo); int nSubItem = lvhitTestInfo.iSubItem; UINT nFlags =   lvhitTestInfo.flags; //nFlags is 0 if the SubItemHitTest fails //Therefore, 0 & <anything> will equal false if (nFlags & LVHT_ONITEMLABEL){  //If it did fall on a list item,  //and it was also hit one of the  //item specific sub-areas we wish to show tool tips for  //Get the client (area occupied by this control  RECT rcClient;  GetClientRect( &rcClient );  //Fill in the TOOLINFO structure  pTI->hwnd = m_hWnd;  pTI->uId = (UINT) (nItem * 100 + nSubItem);  pTI->lpszText = LPSTR_TEXTCALLBACK;  pTI->rect = rcClient;  return pTI->uId; //By returning a unique value per listItem,  //we ensure that when the mouse moves over another list item,  //the tooltip will change }else{  //Otherwise, we aren't interested, so let the message propagate  return -1; }} BOOL CToolTipListCtrl::OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult ){ //VC6.0则用下面这句 //_AFX_THREAD_STATE* pThreadState = AfxGetThreadState(); //VC2003则用这句 AFX_MODULE_THREAD_STATE* pThreadState = AfxGetModuleThreadState(); CToolTipCtrl *pToolTip = pThreadState->m_pToolTip; pToolTip->SetMaxTipWidth(500);  //Handle both ANSI and UNICODE versions of the messageTOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR; if( (pNMHDR->idFrom == (UINT)m_hWnd) &&  ( ((pNMHDR->code == TTN_NEEDTEXTA) && (pTTTA->uFlags & TTF_IDISHWND)) ||  ((pNMHDR->code == TTN_NEEDTEXTW) && (pTTTW->uFlags & TTF_IDISHWND)) ) ){   return FALSE;  }  *pResult = 0;  //Get the mouse position  const MSG* pMessage;  pMessage = GetCurrentMessage();  ASSERT ( pMessage );  CPoint pt;  pt = pMessage->pt; //Get the point from the message  ScreenToClient( &pt );   LVHITTESTINFO lvhitTestInfo;  lvhitTestInfo.pt = pt;  int nItem = SubItemHitTest(&lvhitTestInfo);  int nSubItem = lvhitTestInfo.iSubItem;  UINT nFlags =   lvhitTestInfo.flags;  if( nFlags & LVHT_ONITEMLABEL ){   //在这里设置提示信息显示的内容  m_strToolTipText = GetItemText(nItem,nSubItem) + _T("\nTEST");  pTTTA->lpszText = (LPSTR)(LPWSTR)(LPCWSTR)m_strToolTipText;  pTTTW->lpszText = (LPWSTR)(LPCWSTR)m_strToolTipText;    //{{下面为提供提示信息的另外一种方法   //   CString strTipText;//提示信息内容   //#ifndef _UNICODE   //   if (pNMHDR->code == TTN_NEEDTEXTA)   //    lstrcpyn(pTTTA->szText, strTipText, 80);   //   else   //    _mbstowcsz(pTTTW->szText, strTipText, 80);   //#else   //   if (pNMHDR->code == TTN_NEEDTEXTA)   //    _wcstombsz(pTTTA->szText, strTipText, 80);   //   else   //    lstrcpyn(pTTTW->szText, strTipText, 80);   //#endif   //}}另外一种提示方法结束   return FALSE;   }  return FALSE;}

(1) 

在头文件中定义CToolTipCtrl对象m_ToolTip;

CToolTipCtrl m_ToolTip;

(2)

m_ToolTip.Create(this);//创建对象

m_ToolTip.AddTool( GetDlgItem(IDC_BTN_PLAYSTOP), "连接" );    //lianjie按钮的提示
    m_ToolTip.AddTool( GetDlgItem(IDC_CHECK_VIEW), "本地预览" );  //按钮的提示
 m_ToolTip.AddTool( GetDlgItem(IDC_BTN_BMPCAPTURE), "BMP抓图" );  //按钮的提示
 m_ToolTip.AddTool( GetDlgItem(IDC_BTN_LOCALREC), "本地录像" );  //按钮的提示
 m_ToolTip.AddTool( GetDlgItem(IDC_BTN_TALK), "语音对讲" );  //按钮的提示
 m_ToolTip.AddTool( GetDlgItem(IDC_BTN_RESET), "重启设备" );  //按钮的提示
    m_ToolTip.AddTool( GetDlgItem(IDCANCEL), "退出系统" );  //按钮的提示
 m_ToolTip.AddTool( GetDlgItem(IDC_BTN_CLEAR), "清除消息" );  //按钮的提示,

 

m_ToolTip.SetDelayTime(200);

    m_ToolTip.SetTipTextColor( RGB(0,0,0 ));//设置提示字体颜色

    m_ToolTip.SetTipBkColor( RGB(255,255,255));//设置提示背景颜色

    m_ToolTip.Activate(TRUE);

 

(3)

添加虚函数PreTranslateMessage

BOOL CLAUMp4TestDlg::PreTranslateMessage(MSG* pMsg)
{
 // TODO: Add your specialized code here and/or call the base class
 switch(pMsg->message)

 {
 case WM_MOUSEMOVE:

  m_ToolTip.RelayEvent(pMsg);

 }
 return CDialog::PreTranslateMessage(pMsg);
}

//////////////////////////////////////////////////////////////////////////////////////////////////

为CListCtrl单元格添加提示信息的类

一、思路:
1. 确定鼠标落在哪一个单元格上面
2. 获得该单元格的文字信息
3. 更新tooltip的信息。

 
二、实施
1. 添加CListCtrl的派生类CMyListCtrl

2.添加声明成员变量

[cpp] view plaincopyprint?
  1. CToolTipCtrl m_toolTip;        //文本提示类  
  2. int m_nSubItem;                //存放行号  
  3. int m_nItem;                //存放列号  
  4. BOOL m_bEnableTips;            //是否开启文本提示  

3.初始化成员变量

[cpp] view plaincopyprint?
  1. CMyListCtrl::CMyListCtrl()  
  2. {  
  3.     m_bEnableTips=TRUE;  
  4.     m_toolTip.Create(this);  
  5. }  

4. 为该派生类添加WM_MOUSEMOVE消息
5. 在WM_MOUSEMOVE的消息处理函数中添加如下代码:

[cpp] view plaincopyprint?
  1. void CMyListCtrl::OnMouseMove(UINT nFlags, CPoint point)   
  2. {  
  3.     // TODO: Add your message handler code here and/or call default  
  4.     //如果开启文本提示   
  5.     if(m_bEnableTips)  
  6.     {  
  7.         CString str;  
  8.         LVHITTESTINFO lvhti;  
  9.   
  10.         // 判断鼠标当前所在的位置(行, 列)   
  11.         lvhti.pt = point;      
  12.         SubItemHitTest(&lvhti);  
  13.       
  14.         //如果鼠标移动到另一个单元格内, 则进行处理; 否则, 不做处理   
  15.          if((lvhti.iItem != m_nItem) || (lvhti.iSubItem != m_nSubItem))  
  16.          {  
  17.              // 保存当前鼠标所在的(行,列)  
  18.             m_nItem = lvhti.iItem;  
  19.             m_nSubItem = lvhti.iSubItem;  
  20.   
  21.             // 如果鼠标移动到一个合法的单元格内,则显示新的提示信息  
  22.             // 否则, 不显示提示   
  23.             if((m_nItem != -1) && (m_nSubItem != -1))  
  24.             {  
  25.                  // @@@@@@@@ 在这里修改要显示的提示信息  
  26.                  // 这里仅仅是一个例子---获得当前单元格的文字信息, 并设置为新的提示信息  
  27.                  str = GetItemText(m_nItem ,m_nSubItem);     
  28.                  m_toolTip.AddTool(this, str);   
  29.                  // 显示提示框   
  30.                  m_toolTip.Pop();  
  31.              }  
  32.             else  
  33.             {  
  34.                 m_toolTip.AddTool(this"");  
  35.                 m_toolTip.Pop();  
  36.             }  
  37.          }  
  38.     }  
  39.   
  40.     CListCtrl::OnMouseMove(nFlags, point);  
  41. }  

6.添加虚函数 PreTranslateMessage

[cpp] view plaincopyprint?
  1. BOOL CMyListCtrl::PreTranslateMessage(MSG* pMsg)   
  2. {  
  3.     if(m_toolTip.GetSafeHwnd())  
  4.      {  
  5.          m_toolTip.RelayEvent(pMsg);  
  6.      }    
  7.     return CListCtrl::PreTranslateMessage(pMsg);  
  8. }  
 
 

CToolTipCtrl 如何换行

Tooltip中由一个方法叫做SetMaxTipWidth,MSDN中的描述说是设定Tips窗口的最大宽度,然后就没了。
其实这个方法是使用SDK中的TTM_SETMAXTIPWIDTH 消息,查一下这个消息的描述,就会发现很多内容。
1. 这个方法是设定Tips窗口的最大宽度,in pixel;
2. 如果文字超过这个最大宽度,则control进行自动换行,以空格为换行标志;
3. 如果无法换行(没有空格或\r\n),则显示一行,宽度超过最大宽度。

还有很重要的一点,如果没有设定过宽度,则系统默认宽度为-1,这也是没有设定宽度就不能换行的原因。

试验结果:
1. 一旦设定宽度,\r\n和空格就会同时起作用,只是空格是在一行宽度超过设定宽度时起作用的。