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编码
- BOOL CPreParent::OnToolTipText(UINT, NMHDR* pNMHDR, LRESULT* pResult)
- {
- ASSERT(pNMHDR->code == TTN_NEEDTEXTA || pNMHDR->code == TTN_NEEDTEXTW);
- // UNICODE消息
- TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
- TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
- //TCHAR szFullText[512];
- CString strTipText;
- UINT nID = pNMHDR->idFrom;
- if (pNMHDR->code == TTN_NEEDTEXTA && (pTTTA->uFlags & TTF_IDISHWND) ||
- pNMHDR->code == TTN_NEEDTEXTW && (pTTTW->uFlags & TTF_IDISHWND))
- {
- // idFrom为工具条的HWND
- nID = ::GetDlgCtrlID((HWND)nID);
- }
- if (nID != 0) //不为分隔符
- {
- strTipText.LoadString(nID);
- strTipText = strTipText.Mid(strTipText.Find('\n',0)+1);
- //strTipText = _T("notify string");
- #ifndef _UNICODE
- if (pNMHDR->code == TTN_NEEDTEXTA)
- {
- lstrcpyn(pTTTA->szText, strTipText, sizeof(pTTTA->szText));
- }
- else
- {
- _mbstowcsz(pTTTW->szText, strTipText, sizeof(pTTTW->szText));
- }
- #else
- if (pNMHDR->code == TTN_NEEDTEXTA)
- {
- _wcstombsz(pTTTA->szText, strTipText,sizeof(pTTTA->szText));
- }
- else
- {
- lstrcpyn(pTTTW->szText, strTipText, sizeof(pTTTW->szText));
- }
- #endif
- *pResult = 0;
- //使工具条提示窗口在最上面
- ::SetWindowPos(pNMHDR->hwndFrom, HWND_TOP, 0, 0, 0, 0,
- SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOOWNERZORDER);
- return TRUE;
- }
- return TRUE;
- }
MFC中CListCtrl添加多行提示信息方法
这里是用一个类CToolTipListCtrl实现,它继承自CListCtrl。添加提示信息的时候只需要在OnToolTipText函数中if( nFlags & LVHT_ONITEMLABEL )代码块中设置你要显示的值给m_strToolTipText就可以了。这个时候你就可以为不同的单元格显示不同的提示信息,而且提示信息可以为任意多行,提示信息可以使用“\n”分行。
#pragma once
// CToolTipListCtrl
class 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"
// CToolTipListCtrl
IMPLEMENT_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 message
TOOLTIPTEXTA* 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.添加声明成员变量
- CToolTipCtrl m_toolTip; //文本提示类
- int m_nSubItem; //存放行号
- int m_nItem; //存放列号
- BOOL m_bEnableTips; //是否开启文本提示
CToolTipCtrl m_toolTip; //文本提示类
int m_nSubItem; //存放行号
int m_nItem; //存放列号
BOOL m_bEnableTips; //是否开启文本提示
3.初始化成员变量
- CMyListCtrl::CMyListCtrl()
- {
- m_bEnableTips=TRUE;
- m_toolTip.Create(this);
- }
CMyListCtrl::CMyListCtrl()
{
m_bEnableTips=TRUE;
m_toolTip.Create(this);
}
4. 为该派生类添加WM_MOUSEMOVE消息
5. 在WM_MOUSEMOVE的消息处理函数中添加如下代码:
- void CMyListCtrl::OnMouseMove(UINT nFlags, CPoint point)
- {
- // TODO: Add your message handler code here and/or call default
- //如果开启文本提示
- if(m_bEnableTips)
- {
- CString str;
- LVHITTESTINFO lvhti;
- // 判断鼠标当前所在的位置(行, 列)
- lvhti.pt = point;
- SubItemHitTest(&lvhti);
- //如果鼠标移动到另一个单元格内, 则进行处理; 否则, 不做处理
- if((lvhti.iItem != m_nItem) || (lvhti.iSubItem != m_nSubItem))
- {
- // 保存当前鼠标所在的(行,列)
- m_nItem = lvhti.iItem;
- m_nSubItem = lvhti.iSubItem;
- // 如果鼠标移动到一个合法的单元格内,则显示新的提示信息
- // 否则, 不显示提示
- if((m_nItem != -1) && (m_nSubItem != -1))
- {
- // @@@@@@@@ 在这里修改要显示的提示信息
- // 这里仅仅是一个例子---获得当前单元格的文字信息, 并设置为新的提示信息
- str = GetItemText(m_nItem ,m_nSubItem);
- m_toolTip.AddTool(this, str);
- // 显示提示框
- m_toolTip.Pop();
- }
- else
- {
- m_toolTip.AddTool(this, "");
- m_toolTip.Pop();
- }
- }
- }
- CListCtrl::OnMouseMove(nFlags, point);
- }
void CMyListCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
//如果开启文本提示
if(m_bEnableTips)
{
CString str;
LVHITTESTINFO lvhti;
// 判断鼠标当前所在的位置(行, 列)
lvhti.pt = point;
SubItemHitTest(&lvhti);
//如果鼠标移动到另一个单元格内, 则进行处理; 否则, 不做处理
if((lvhti.iItem != m_nItem) || (lvhti.iSubItem != m_nSubItem))
{
// 保存当前鼠标所在的(行,列)
m_nItem = lvhti.iItem;
m_nSubItem = lvhti.iSubItem;
// 如果鼠标移动到一个合法的单元格内,则显示新的提示信息
// 否则, 不显示提示
if((m_nItem != -1) && (m_nSubItem != -1))
{
// @@@@@@@@ 在这里修改要显示的提示信息
// 这里仅仅是一个例子---获得当前单元格的文字信息, 并设置为新的提示信息
str = GetItemText(m_nItem ,m_nSubItem);
m_toolTip.AddTool(this, str);
// 显示提示框
m_toolTip.Pop();
}
else
{
m_toolTip.AddTool(this, "");
m_toolTip.Pop();
}
}
}
CListCtrl::OnMouseMove(nFlags, point);
}
6.添加虚函数 PreTranslateMessage
- BOOL CMyListCtrl::PreTranslateMessage(MSG* pMsg)
- {
- if(m_toolTip.GetSafeHwnd())
- {
- m_toolTip.RelayEvent(pMsg);
- }
- return CListCtrl::PreTranslateMessage(pMsg);
- }
BOOL CMyListCtrl::PreTranslateMessage(MSG* pMsg)
{
if(m_toolTip.GetSafeHwnd())
{
m_toolTip.RelayEvent(pMsg);
}
return CListCtrl::PreTranslateMessage(pMsg);
}
CToolTipCtrl 如何换行
Tooltip中由一个方法叫做SetMaxTipWidth,MSDN中的描述说是设定Tips窗口的最大宽度,然后就没了。
其实这个方法是使用SDK中的TTM_SETMAXTIPWIDTH 消息,查一下这个消息的描述,就会发现很多内容。
1. 这个方法是设定Tips窗口的最大宽度,in pixel;
2. 如果文字超过这个最大宽度,则control进行自动换行,以空格为换行标志;
3. 如果无法换行(没有空格或\r\n),则显示一行,宽度超过最大宽度。
还有很重要的一点,如果没有设定过宽度,则系统默认宽度为-1,这也是没有设定宽度就不能换行的原因。
试验结果:
1. 一旦设定宽度,\r\n和空格就会同时起作用,只是空格是在一行宽度超过设定宽度时起作用的。