怎样给VC中的List控件添加ToolTip
VC6的List控件默认是不能为subitem提供tooltip的,只有通过重写CListCtrl类来实现。在网上找了一个写好的CToolTipListCtrl类可以显示该功能,只需调用即可。具体步骤如下:
1.将ToolTipListCtrl.h和ToolTipListCtrl.cpp加入工程。
2.为List控件添加相应的变量CListCtrl m_lstObject。
3.用CToolTipListCtrl替换上面的CListCtrl,当然还要加入相应的头文件“#include "ToolTipListCtrl.h"”。
4.设置列表的扩展样式,使之包含LVS_EX_INFOTIP样式。
m_lstObject.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_INFOTIP);
5.步骤4也可以改为
m_lstObject.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
m_lstObject.EnableToolTips(TRUE);
6.编译运行程序。效果见下图:
是不是很简单呢,你也赶快试试吧。
下面是ToolTipListCtrl.h和ToolTipListCtrl.cpp源码:
#if !defined(AFX_TOOLTIPLISTCTRL_H__EA17BA6D_ADD2_49E3_AB67_45B65316D19F__INCLUDED_) #define AFX_TOOLTIPLISTCTRL_H__EA17BA6D_ADD2_49E3_AB67_45B65316D19F__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 // ToolTipListCtrl.h : header file // ///////////////////////////////////////////////////////////////////////////// // CToolTipListCtrl window #include <afxtempl.h> ///////////////////////////////////////////////////////////////////////////// // CToolTipListCtrl, v.1.0 // // A CListCtrl derived class that // can display per SubItem tooltips by itself // // Author: Jo鉶 Filipe de Castro Ferreira (jfilipe@isr.uc.pt) // Based on Nate Maynard's (nate.maynard@neomation.com) CToolTipTreeCtrl // // Last Modified: 7/11/2001 // // License: Quoting Nate Maynard, // "use it however you want. If it helps you out, drop me a line and let me know. :-)" // // Disclaimer: This code comes with no warranty of any kind whatsoever. Use at your own risk. // ///////////////////////////////////////////////////////////////////////////// //The initial state of m_wHitMask #define INITIAL_HITMASK LVHT_ONITEMLABEL class CToolTipListCtrl : public CListCtrl { // Construction public: CToolTipListCtrl(); // Attributes public: protected: // Map's SubItems to related tooltip text CMapStringToString m_ToolTipMap; // A bit mask of LVHT_* flags the control will show tooltips for WORD m_wHitMask; // Operations public: // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CToolTipListCtrl) //}}AFX_VIRTUAL // Implementation public: //** CWnd Overrides ** //Provide our own logic for HitTests, specifically, make ToolHitTests respond per SubItem virtual int OnToolHitTest(CPoint point, TOOLINFO * pTI) const; //** CTreeCtrl Overrides ** //Overriding the Delete functions makes sure m_ToolTipMap doesn't have excess mappings virtual BOOL DeleteAllItems( ); virtual BOOL DeleteItem( int nItem ); virtual BOOL SetItemText( int nItem, int nSubItem, LPTSTR lpszText ); //** Additional Functions ** //Set the TVHT_* flags that will trigger the display of a tooltip WORD SetToolTipHitMask(WORD wHitMask); //Clear all tooltips virtual void DeleteAllToolTips(); //Set the tooltip text for a specific SubItem virtual BOOL SetItemToolTipText( int nItem, int nSubItem, LPCTSTR lpszToolTipText ); //Retrieves the tooltip text for a specific SubItem virtual CString GetItemToolTipText( int nItem, int nSubItem ); virtual ~CToolTipListCtrl(); // Generated message map functions protected: //{{AFX_MSG(CToolTipListCtrl) // NOTE - the ClassWizard will add and remove member functions here. //}}AFX_MSG //Respondes to the TTN_NEEDTEXT* messages, provides the text of a tooltip virtual afx_msg BOOL OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult ); DECLARE_MESSAGE_MAP() }; ///////////////////////////////////////////////////////////////////////////// //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif // !defined(AFX_TOOLTIPLISTCTRL_H__EA17BA6D_ADD2_49E3_AB67_45B65316D19F__INCLUDED_)
// ToolTipListCtrl.cpp : implementation file // #include "stdafx.h" #include "ToolTipListCtrl.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CToolTipListCtrl CToolTipListCtrl::CToolTipListCtrl() { m_wHitMask = INITIAL_HITMASK; } CToolTipListCtrl::~CToolTipListCtrl() { // Cleanup when destroyed DeleteAllToolTips(); } BEGIN_MESSAGE_MAP(CToolTipListCtrl, CListCtrl) //{{AFX_MSG_MAP(CToolTipListCtrl) // NOTE - the ClassWizard will add and remove mapping macros here. //}}AFX_MSG_MAP //Trap all TTN_NEEDTEXT* Messages //TTN_NEEDTEXT* messages are sent when a ToolTipCtrl wants a control //to provide it with text to display as the tooltip. //Specifically, when the TOOLINFO structure passed back to the ToolTipCtrl //after ::OnToolHitTest has it's lpszText memeber set to LPSTR_TEXTCALLBACK. ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText) ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CToolTipListCtrl message handlers 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 & m_wHitMask) { // 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 ) { // Handle both ANSI and UNICODE versions of the message TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR; TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR; // Ignore messages from the built in tooltip, we are processing them internally 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; CString strTipText; // Get the mouse position const MSG* pMessage; pMessage = GetCurrentMessage(); ASSERT ( pMessage ); CPoint pt; pt = pMessage->pt; // Get the point from the message ScreenToClient( &pt ); // Convert the point's coords to be relative to this control // See if the point falls onto a list item LVHITTESTINFO lvhitTestInfo; lvhitTestInfo.pt = pt; int nItem = SubItemHitTest(&lvhitTestInfo); int nSubItem = lvhitTestInfo.iSubItem; UINT nFlags = lvhitTestInfo.flags; // nFlags is 0 if the SubItemHitTest fails // Therefore, 0 & <anything> will equal false if( nFlags & m_wHitMask ) { // 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 // Lookup the list item's text in the ToolTip Map CString strKey; strKey.Format(_T("%d"), nItem * 100 + nSubItem); if( m_ToolTipMap.Lookup(strKey, strTipText ) ) { // If there was a CString associated with the list item, // copy it's text (up to 80 characters worth, limitation of the TOOLTIPTEXT structure) // into the TOOLTIPTEXT structure's szText member // Deal with UNICODE #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; // We found a tool tip, // tell the framework this message has been handled //////////////////////////////////////////////////////////////////////////////// // ****** Special note ***** // // Still don't understand why the function must return FALSE for CListCtrl // so as not to cause flickering, as opposed to Nate Maynard's derivation // from CTreeCtrl. // I have experimented with disabling Tooltips for the control // and found out that a "ghost" tooltip appears for a fraction of a second... // // I am completely at a loss... // Seems to work, though... // //////////////////////////////////////////////////////////////////////////////// } } return FALSE; // We didn't handle the message, // let the framework continue propagating the message } // Sets the tooltip text for a specific item BOOL CToolTipListCtrl::SetItemToolTipText( int nItem, int nSubItem, LPCTSTR lpszToolTipText ) { CString strKey; strKey.Format(_T("%d"), nItem * 100 + nSubItem); m_ToolTipMap.SetAt( strKey, lpszToolTipText ); return TRUE; } // Retrieve the tooltip text for a specific list item CString CToolTipListCtrl::GetItemToolTipText( int nItem, int nSubItem ) { CString itemToolTipText; CString strKey; strKey.Format(_T("%d"), nItem * 100 + nSubItem); if( !m_ToolTipMap.Lookup( strKey, itemToolTipText ) ) { itemToolTipText = ""; } return itemToolTipText; } WORD CToolTipListCtrl::SetToolTipHitMask( WORD wHitMask ) { WORD oldHitMask = m_wHitMask; m_wHitMask = wHitMask; return oldHitMask; } void CToolTipListCtrl::DeleteAllToolTips() { m_ToolTipMap.RemoveAll(); } BOOL CToolTipListCtrl::DeleteAllItems( ) { // Call the base class method BOOL retVal = CListCtrl::DeleteAllItems(); if( retVal ) { // If it succeeded, remove all tooltips DeleteAllToolTips(); } return retVal; } BOOL CToolTipListCtrl::DeleteItem( int nItem ) { // Call the base class method BOOL retVal = CListCtrl::DeleteItem( nItem ); if( retVal ) { // If it succeeded, remove it's tooltip from the map LVCOLUMN *lvColumn = (LVCOLUMN*) malloc (sizeof(LVCOLUMN)); for (int i = 0; GetColumn(i, lvColumn) != 0; i++); { CString strKey; strKey.Format(_T("%d"), nItem * 100 + i); m_ToolTipMap.RemoveKey( strKey ); } // 李鸿喜2012年11月30日添加 free( lvColumn ); } return retVal; } /* */ BOOL CToolTipListCtrl::SetItemText( int nItem, int nSubItem, LPTSTR lpszText ) { // Call the base class method BOOL retVal = CListCtrl::SetItemText( nItem, nSubItem, lpszText ); if( retVal ) { SetItemToolTipText( nItem, nSubItem, lpszText ); } return retVal; }
本程序在WinXP SP3+VC6下测试通过。