Click here to Skip to main content
15,867,308 members
Articles / Desktop Programming / MFC
Article

ListBox With ToolTip Support

Rate me:
Please Sign up or sign in to vote.
4.78/5 (17 votes)
4 Jan 20022 min read 216.1K   4.2K   48   34
A CListBox derived class providing Item tooltips

Sample Image - CExListBoc.gif

Introduction

I've needed a simple listbox with tool tip support for my project, i couldn't find a listbox derived class that will do job. Salman A Khilji offers tool tip support in his article "List Box with ToolTips", but he his offering a multi-line tool tip which display's a pre-defined string as set in the dialog function. Also, the tips are always shown in the upper right corner.

In order to add tool tips support do the following:

  1. Add ExListBox.cpp and ExListBox.h to your project. 
  2. Add include "ExListBox.h" to the header file of your dialog class. 
  3. Add a list box control to your dialog. 
  4. Use the ClassWizard to add a member variable of type CListBox for the list box you just added.
  5. Manually change the member variable type to CExListBox in your header file of your dialog class. 

That's it, your list box will now display tool tip according to the item's text!

CExListBox - Explanation 

First we must enable the tool tip, so we add the following line to the PreSubclassWindow function:

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

CListBox::PreSubclassWindow();
EnableToolTips(TRUE);

}

Now , we need to override OnToolHitTest function in order  to provide the struct(s) for the ListBox.

int CExListBox::OnToolHitTest(CPoint point, TOOLINFO * pTI) const
{
    int row;
    RECT cellrect; // cellrect - to hold the bounding rect
    BOOL tmp = FALSE;
    row = ItemFromPoint(point,tmp); //we call the ItemFromPoint function to determine the row,
    //note that in NT this function may fail use the ItemFromPointNT member function
    if ( row == -1 ) 
        return -1;

    //set up the TOOLINFO structure. GetItemRect(row,&cellrect);
    GetItemRect(row,&cellrect);
    pTI->rect = cellrect;
    pTI->hwnd = m_hWnd;
    pTI->uId = (UINT)((row)); //The ‘uId’ is assigned a value according to the row value.
    pTI->lpszText = LPSTR_TEXTCALLBACK;  //Send a TTN_NEEDTEXT messages 
    return pTI->uId;

}

As you can see , we first find out on which item the mouse points using the ItemFromPoint function . NOTE: in NT this function may fail, so use the

ItemFromPointNT 
function (included in this class )

After we obtained the item pointed by mouse , we need to assign the item tool tip text , we assign to the TOOLINFO text member the LPSTR_TEXTCALLBACK which sends TTN_NEEDTEXT messages.

All we need to do now , is to supply handles for TTN_NEEDTEXT messages (wide and ansi ).

In the implementation file we add :

BEGIN_MESSAGE_MAP(CExListBox, CListBox)
//{{AFX_MSG_MAP(CExListBox)
// NOTE - the ClassWizard will add and remove mapping macros here.

//}}AFX_MSG_MAP
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)
END_MESSAGE_MAP()

And then add the OnToolTipText function :

BOOL CExListBox::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;  //list box item index 
    GetText( nID ,strTipText); //get item text 

//display item text as tool tip 
#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; 
}

The source code

//
//#include "stdafx.h"

#include "ExListBox.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


/////////////////////////////////////////////////////////////////////////////
// CExListBox

CExListBox::CExListBox()
{
}

CExListBox::~CExListBox()
{
}


BEGIN_MESSAGE_MAP(CExListBox, CListBox)
    //{{AFX_MSG_MAP(CExListBox)
        // NOTE - the ClassWizard will add and remove mapping macros here.

    //}}AFX_MSG_MAP
    ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
    ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CExListBox message handlers

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

    CListBox::PreSubclassWindow();
    EnableToolTips(TRUE);

}

int CExListBox::OnToolHitTest(CPoint point, TOOLINFO * pTI) const
{
    int row;
    RECT cellrect;   // cellrect        - to hold the bounding rect
    BOOL tmp = FALSE;
    row  = ItemFromPoint(point,tmp);  //we call the ItemFromPoint function to determine the row,
    //note that in NT this function may fail  use the ItemFromPointNT member function

    if ( row == -1 ) 
        return -1;

    //set up the TOOLINFO structure. GetItemRect(row,&cellrect);
    GetItemRect(row,&cellrect);
    pTI->rect = cellrect;
    pTI->hwnd = m_hWnd;
    pTI->uId = (UINT)((row));   //The ‘uId’ is assigned a value according to the row value.
    pTI->lpszText = LPSTR_TEXTCALLBACK;
    return pTI->uId;

}


//Define OnToolTipText(). This is the handler for the TTN_NEEDTEXT notification from 
//support ansi and unicode 
BOOL CExListBox::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;

    
    GetText( nID ,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
    *pResult = 0;

    return TRUE;    
}




UINT CExListBox::ItemFromPoint2(CPoint pt, BOOL& bOutside) const

// CListBox::ItemFromPoint does not work on NT.

{
    int nFirstIndex, nLastIndex;
    //GetFirstAndLastIndex(nFirstIndex, nLastIndex);
    nFirstIndex = GetTopIndex();
    nLastIndex = nFirstIndex  + GetCount(); 


    
    bOutside = TRUE;
    
    CRect Rect;
    int nResult = -1;
    
    for (int i = nFirstIndex; nResult == -1 && i <= nLastIndex; i++)
    {
        if (GetItemRect(i, &Rect) != LB_ERR)
        {
            if (Rect.PtInRect(pt))
            {
                nResult  = i;
                bOutside = FALSE;
            }
        }
        
    }
    
    return nResult;
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionFixes for no TTN_NEEDTEXT, no tip, tip under listbox in CComboBox list Pin
GregSmith23-Jan-12 1:01
GregSmith23-Jan-12 1:01 
GeneralCould provide the details of the license this code it shared under is it COPL Pin
PSVN Roy13-Oct-10 7:18
PSVN Roy13-Oct-10 7:18 
Generalproblem found when 2 listboxes on a dialog. Pin
Member 37416425-Feb-08 22:03
Member 37416425-Feb-08 22:03 
QuestionRe: problem found when 2 listboxes on a dialog. Pin
David Crow6-May-09 3:05
David Crow6-May-09 3:05 
Did you remember to call EnableToolTips(TRUE) in OnInitDialog()?

"Old age is like a bank account. You withdraw later in life what you have deposited along the way." - Unknown

"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons


GeneralSubclassed CListBox don't receive TTN_NEEDTEXT Pin
k200v314-Nov-07 4:29
k200v314-Nov-07 4:29 
GeneralRe: Subclassed CListBox don't receive TTN_NEEDTEXT Pin
Member 32291892-Sep-09 23:27
Member 32291892-Sep-09 23:27 
GeneralI add \r\n in tooltip text, but the tooltip still showed as a single line! Pin
Tcpip20051-Nov-05 19:29
Tcpip20051-Nov-05 19:29 
GeneralThank you for your work. Pin
David.Kelly26-Aug-05 10:30
David.Kelly26-Aug-05 10:30 
QuestionHow to delay the tooltip text? Pin
daveice21-Aug-05 20:31
daveice21-Aug-05 20:31 
GeneralTooltip Flickeing in HTML Pin
Anonymous28-Aug-04 0:30
Anonymous28-Aug-04 0:30 
GeneralToolTip For ComboBox Pin
BitsAndBytes29-Jul-04 23:19
BitsAndBytes29-Jul-04 23:19 
GeneralSelective tooltips Pin
andrewtruckle4-Mar-04 5:15
andrewtruckle4-Mar-04 5:15 
GeneralRe: Selective tooltips Pin
Chunyun26-Jul-04 12:14
Chunyun26-Jul-04 12:14 
GeneralRe: Selective tooltips Pin
andrewtruckle26-Jul-04 19:52
andrewtruckle26-Jul-04 19:52 
GeneralRe: Selective tooltips Pin
Chunyun27-Jul-04 5:59
Chunyun27-Jul-04 5:59 
GeneralRe: Selective tooltips Pin
andrewtruckle27-Jul-04 19:15
andrewtruckle27-Jul-04 19:15 
GeneralRe: Selective tooltips Pin
Chunyun29-Jul-04 8:18
Chunyun29-Jul-04 8:18 
GeneralRe: Selective tooltips Pin
Anonymous13-Aug-04 8:24
Anonymous13-Aug-04 8:24 
GeneralRe: Selective tooltips Pin
Chunyun13-Aug-04 16:49
Chunyun13-Aug-04 16:49 
General_mbstowcsz() on VS.NET Pin
Amit Gefen22-Jan-04 11:24
Amit Gefen22-Jan-04 11:24 
GeneralTooltip Flickering Pin
Karen03021-Jan-04 3:27
Karen03021-Jan-04 3:27 
GeneralEmpty list boxes go boom... Pin
davant29-Apr-03 10:45
davant29-Apr-03 10:45 
GeneralRe: Empty list boxes go boom... Pin
ran wainstein3-May-03 23:17
ran wainstein3-May-03 23:17 
QuestionHow to Hook TTN_NEEDTEXT? Pin
4888558427-Apr-03 22:28
suss4888558427-Apr-03 22:28 
QuestionWhy this project doesn't work on my machine? I cannot see the tooltip. Can you tell me ? Pin
Anonymous16-Oct-02 15:43
Anonymous16-Oct-02 15:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.