怎样给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 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 )
{