CTreeCtrl With ToolTip Based On the Item Data

Environment: VC6 SP4, NT4 SP3,Win 95/98/ME

Introduction

Let’s say you want a tree ctrl with tool tip support. You can find some good articles explaining you exactly what to do ( look in the treeview section in code guru, Zafir Anjum’s article will give you all the information you need. What if you want to display a custom tool tip for each item? One which will display any kind of data and not only the tree item text?

I searched for a class that would give me the freedom to display any tool tip I want and couldn’t find any. You can use this CTreeCtrl derived class if you have the same problam.

This article will not focus on the technical sides of adding tool tip support to your tree ctrl. For that, use the articles I’ve listed above.

Before starting, I would like to thanks Yaniv Ben Ari for his great idea.

What is this Class?

CTreeCtrlCh is a CTreeCtrl derived class, which display tool tip according to the item data. You can attach any string you like to the any tree item using SetItemData() function. This text will be displayed as a tool tip.

How this class works?

This class uses an abstract class as an ItemData templete. The user must derived it’s own ItemData class from the abstract class, and must implement a virtual function called : GetToolTipString(). This function returns a CString object that will be displayed as a tool tip. The user should construct this returned CString object according to his Own ItemData class. Sound a little complicated? It’s not, as the next section will show you.

How To Use This Class?

  • Add the files you’ve downloaded to your project directoy and add them to your project.
  • Add a TreeCtrl to your dialog and assign it a member using the control wizard
  • Add the following statement to your dialog header file:
    #include "TreeCtrlCh.h"
  • Change the tree control variable type to CTreeCtrlch
  • In the dialog header file construct a new class derived from ItemDataABSTRACT as public. This class will be use as your tree item data. Add any data member you want. Most important is to add the GetToolTipString(), (pure virtual, must be implemented)
  • In your dialog implementation file, you need to implement the GetToolTipString() function. This function MUST return a CString object, this object will be displayed as the item tool tip. In this function you can manipulate the item data members and construct any string you want such as additional information on the item, dates, size, and etc.
  • When you to add item data, declare a pointer to the class you’ve derived from ItemDataABSTRACT. Assign data to it’s memberand use SetItemData to add the ItemData pointer.
  • There is no need to delete the memory allocated, the CTreeCtrlch will free all allocated memory used for item data.

 


#include “stdafx.h”
#include “TreeCtrlCh.h”
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

///////////////////////////////////////
// CTreeCtrlCh

CTreeCtrlCh::CTreeCtrlCh()
{
}
CTreeCtrlCh::~CTreeCtrlCh()
{
}
BEGIN_MESSAGE_MAP(CTreeCtrlCh, CTreeCtrl)
//{{AFX_MSG_MAP(CTreeCtrlCh)
ON_WM_LBUTTONDOWN()
ON_WM_DESTROY()
//}}AFX_MSG_MAP
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW,
0,
0xFFFF,
OnToolTipText)
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA,
0,
0xFFFF,
OnToolTipText)
END_MESSAGE_MAP()
///////////////////////////////////////
// CTreeCtrlCh message handlers

void CTreeCtrlCh::PreSubclassWindow()
{
// TODO: Add your specialized code here
// and/or call the base class

CTreeCtrl::PreSubclassWindow();
EnableToolTips(TRUE);
}
int CTreeCtrlCh::OnToolHitTest(CPoint point,
TOOLINFO * pTI) const
{
RECT rect;
UINT nFlags;
HTREEITEM hitem = HitTest( point, &nFlags );
if( nFlags & TVHT_ONITEMLABEL )
{
GetItemRect( hitem, &rect, TRUE );
pTI->hwnd = m_hWnd;
pTI->uId = (UINT)hitem;
pTI->lpszText = LPSTR_TEXTCALLBACK;
pTI->rect = rect;
return pTI->uId;
}
return -1;
}
//here we supply the text for the item
BOOL CTreeCtrlCh::OnToolTipText( UINT id,
NMHDR * pNMHDR,
LRESULT * pResult )
{
// need to handle both ANSI and UNICODE
// versions of the message

TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
CString strTipText;
UINT nID = pNMHDR->idFrom;
// Do not process the msg from built in tooltip
if( nID == (UINT)m_hWnd &&
(( pNMHDR->code == TTN_NEEDTEXTA &&
pTTTA->uFlags & TTF_IDISHWND ) ||
( pNMHDR->code == TTN_NEEDTEXTW &&
pTTTW->uFlags & TTF_IDISHWND ) ) )
return FALSE;
// Get the mouse position
const MSG* pMessage;
CPoint pt;
pMessage = GetCurrentMessage(); // get mouse pos
ASSERT ( pMessage );
pt = pMessage->pt;
ScreenToClient( &pt );
UINT nFlags;
HTREEITEM hitem =
HitTest( pt, &nFlags ); //Get item pointed by mouse
strTipText.Format( “%s”,
GetItemText( (HTREEITEM ) nID)); //get item text
//// here we take the item data , cast it to
//// ItemDataABSTRACT and call the virtual function

DWORD dw =
GetItemData((HTREEITEM ) nID); //get item data
ItemDataABSTRACT* ItemData =
(ItemDataABSTRACT*)dw; //CAST item data
if (ItemData!=NULL)
{
CString s =
ItemData->GetToolTipString(); //pure virtual function
strTipText=” ” + s; //add node text to node data text
}
#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
*pResult = 0;

return TRUE; // message was handled
}

//delete all allocated mamory for item data
void CTreeCtrlCh::CleanItemData()
{
HTREEITEM root = GetFirstVisibleItem();
if (root==NULL)
return ;
do
{

DWORD data = GetItemData(root);
if (data!=NULL)
{
ItemDataABSTRACT* ItemData =
(ItemDataABSTRACT*)data;

delete ItemData ;
}
DeleteBranchData(root);

}while ((root = GetNextSiblingItem(root))!=NULL);

}
void CTreeCtrlCh::OnDestroy()
{
CleanItemData();
CTreeCtrl::OnDestroy();

// TODO: Add your message handler code here

}
void CTreeCtrlCh::DeleteBranchData( HTREEITEM hti)
{
if( ItemHasChildren( hti ) )
{

hti = GetChildItem( hti );
do
{

DWORD data = GetItemData(hti);
if (data!=NULL)
{
ItemDataABSTRACT* ItemData =
(ItemDataABSTRACT*)data;

delete ItemData ;
}

DeleteBranchData( hti);
}while( (hti = GetNextSiblingItem( hti )) != NULL );
}

}
/////////////////HEADER FILE///////////////////
class ItemDataABSTRACT
{

public:
virtual CString GetToolTipString() = 0;

virtual ~ItemDataABSTRACT(){};

protected:
ItemDataABSTRACT(){};

};

class CTreeCtrlCh : public CTreeCtrl
{
// Construction
public:
CTreeCtrlCh();
int OnToolHitTest(CPoint point, TOOLINFO * pTI) const;
void CleanItemData();
BOOL OnToolTipText( UINT id,
NMHDR * pNMHDR,
LRESULT * pResult );
void DeleteBranchData( HTREEITEM hti);

// Attributes
public:

// Operations
public:

// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CTreeCtrlCh)

protected:
virtual void PreSubclassWindow();
//}}AFX_VIRTUAL
// Implementation

public:
virtual ~CTreeCtrlCh();
// Generated message map functions
protected:
//{{AFX_MSG(CTreeCtrlCh)
afx_msg void OnDestroy();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};

Downloads

Download demo project – 30.1 Kb

Download source – 2.43 Kb

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read