Click here to Skip to main content
15,886,919 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.6K   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

 
AnswerRe: Why this project doesn't work on my machine? I cannot see the tooltip. Can you tell me ? Pin
Anthony_Yio22-Oct-02 16:23
Anthony_Yio22-Oct-02 16:23 
GeneralSmall, nontrivial, bug Pin
Srdjan Herak23-Jan-02 7:08
Srdjan Herak23-Jan-02 7:08 
GeneralRe: Small, nontrivial, bug Pin
Srdjan Herak24-Jan-02 3:03
Srdjan Herak24-Jan-02 3:03 
GeneralRe: Small, nontrivial, bug Pin
sortfish31-Jan-04 20:04
sortfish31-Jan-04 20:04 
GeneralRe: Small, nontrivial, bug Pin
Hidde Wallaart13-Oct-04 23:13
Hidde Wallaart13-Oct-04 23:13 
GeneralNow I see what you mean Pin
Hidde Wallaart14-Oct-04 2:25
Hidde Wallaart14-Oct-04 2:25 
GeneralRe: Small, nontrivial, bug Pin
mxjmorrise9-Dec-06 8:19
mxjmorrise9-Dec-06 8:19 
GeneralAnother Way.... Pin
Gavin Taylor6-Jan-02 12:01
professionalGavin Taylor6-Jan-02 12:01 
GeneralRe: Another Way.... Pin
ran wainstein6-Jan-02 22:03
ran wainstein6-Jan-02 22:03 

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.