List control multiline tooltip(DataTip)



Click here for larger image

For end user, The list control that has long and multiple columns can be real hassle... Scrolling up and down, scrolling left and right, and resizing truncated column string. For this reason, almost all of the list control based control has ToolTip and/or TitleTip. Even ToolTip or TitleTip list controls, however, sometimes can't be enough to make a really good user-friendly list control.

This article show you a sort of data tip list control plus sophisticated(?) header tool tip.

Implementing data tip in list control is quite easy. All the functions you concern about is following two functions.

OnToolHitTest() is for detecting mouse movement and retriving list control item on which mouse is on, and OnToolTipText() is for supplying actual tip text to display.

Like OnMouseMove(), OnToolHitTest() is called every time mouse moves, and at this time, you can find current row and fill up TOOLINFO structure with some infomations

int CDataTipListCtrl::OnToolHitTest(CPoint point, TOOLINFO * pTI) const
{
  CRect rect;
  GetClientRect(&rect);
  if(rect.PtInRect(point))
  {
    if(GetItemCount())
    {
      int nTopIndex = GetTopIndex();
      int nBottomIndex = nTopIndex + GetCountPerPage();
      if(nBottomIndex > GetItemCount()) 
         nBottomIndex = GetItemCount();
      for(int nIndex = nTopIndex; 
          nIndex < = nBottomIndex; nIndex++)
      {
        GetItemRect(nIndex, rect, LVIR_BOUNDS);
        if(rect.PtInRect(point))
        {
          pTI->hwnd = m_hWnd;
          pTI->uId = (UINT)(nIndex+1);
          pTI->lpszText = LPSTR_TEXTCALLBACK;
          pTI->rect = rect;
          return pTI->uId;
        }
      }
    }
  }

  return -1;
}

After some delay, OnToolTipText() function is called. in this function, you supply actual tip text to display.

BOOL CDataTipListCtrl::OnToolTipText(UINT id, 
                                          NMHDR* pNMHDR, 
                                          LRESULT* pResult)
{
  // I want to implement this in PreSubclassWindow(), 
  //      but it crashes.
  if(!m_bToolTipCtrlCustomizeDone)
  {
    AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
    CToolTipCtrl *pToolTip = pThreadState->m_pToolTip;
    // Set max tip width in pixel.
    // you can change delay time, tip text or background 
    //   color also. enjoy yourself!
    pToolTip->SetMaxTipWidth(500);
    m_bToolTipCtrlCustomizeDone = TRUE;
  }

  // need to handle both ANSI and UNICODE versions of 
  //    the message
  TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
  TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
  UINT nID = pNMHDR->idFrom;

  if(nID == 0)    // Notification in NT from automatically
    return FALSE; // created tooltip

  int nItem = nID - 1;
  CString strTip;
  TCHAR buf[MAX_TIP_LENGTH+1];
  HDITEM hdCol;
  hdCol.mask = HDI_TEXT;
  hdCol.pszText = buf;
  hdCol.cchTextMax = MAX_TIP_LENGTH; 
  int nNumCol = m_Header.GetItemCount();
  for(int col=0; col < nNumCol; col++)
  {
    m_Header.GetItem(col, &hdCol);
    strTip += hdCol.pszText;
    strTip += _T(": ");
    strTip += GetItemText(nItem, col);
    if(col < nNumCol-1) strTip += _T('\n');
  }

#ifndef _UNICODE
  if(pNMHDR->code == TTN_NEEDTEXTA)
  {
    if(m_pchTip != NULL)
      delete m_pchTip;

    m_pchTip = new TCHAR[strTip.GetLength()+1];
    lstrcpyn(m_pchTip, strTip, strTip.GetLength());
    m_pchTip[strTip.GetLength()] = 0;
    pTTTW->lpszText = (WCHAR*)m_pchTip;
  }
  else
  {
    if(m_pwchTip != NULL)
      delete m_pwchTip;

    m_pwchTip = new WCHAR[strTip.GetLength()+1];
    _mbstowcsz(m_pwchTip, strTip, strTip.GetLength());
    m_pwchTip[strTip.GetLength()] = 0; // end of text
    pTTTW->lpszText = (WCHAR*)m_pwchTip;
  }
#else
  if(pNMHDR->code == TTN_NEEDTEXTA)
  {
    if(m_pchTip != NULL)
      delete m_pchTip;

    m_pchTip = new TCHAR[strTip.GetLength()+1];
    _wcstombsz(m_pchTip, strTip, strTip.GetLength());
    m_pchTip[strTip.GetLength()] = 0; // end of text
    pTTTA->lpszText = (LPTSTR)m_pchTip;
  }
  else
  {
    if(m_pwchTip != NULL)
      delete m_pwchTip;

    m_pwchTip = new WCHAR[strTip.GetLength()+1];
    lstrcpyn(m_pwchTip, strTip, strTip.GetLength());
    m_pwchTip[strTip.GetLength()] = 0;
    pTTTA->lpszText = (LPTSTR) m_pwchTip;
  }
#endif

  *pResult = 0;

  return TRUE;    // message was handled
}

As you already noticed, to increase tip text's length, I introduced m_pchTip, m_pwchTip(for unicode) data member. Without this, you can't display a tip more than 80 characters. And allocated memory for tip text is always deleted next call, but the last call is not, so you must delete it in the destructor. Like this,

CDataTipListCtrl::~CDataTipListCtrl()
{
  if(m_pchTip != NULL)
    delete m_pchTip;

  if(m_pwchTip != NULL)
    delete m_pwchTip;
}

And for safety reason, this code should go to constructor too.

CDataTipListCtrl::CDataTipListCtrl()
{
  m_pchTip = NULL;
  m_pwchTip = NULL;
  m_bToolTipCtrlCustomizeDone = FALSE;
}

pToolTip->SetMaxTipWidth(500); is quite essential to this article. Without this line, tool tip never display "multi line" tool tips. m_bToolTipCtrlCustomizeDone data member is for "Only once" purpose.

Don't forget to mapping messages for above two function by inserting the following two lines in you messge map macro.

ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)

And last, in PreSubclassWindow(), Enable our tool tip.

void CDataTipListCtrl::PreSubclassWindow() 
{
  // TODO: Add your specialized code here and/or call 
  //   the base class
  SetExtendedStyle(LVS_EX_FULLROWSELECT); // Enables full row
                                          //   selection
  EnableToolTips(); // Enables list contrl ToolTip control
  m_Header.SubclassDlgItem(0, this); // Replaces new header 
                                     //  control with default
                                     //  list contrl header 
                                     //  control.

  CListCtrl::PreSubclassWindow();
}

Downloads

Download demo project - 50Kb


Comments

  • UNICODE

    Posted by Narmada on 06/27/2013 03:24am

    This program is not working in unicode...

    Reply
  • Come across who's preaching about gucci and also as to why you should feel concerned.

    Posted by BobHotgloff on 05/02/2013 03:11am

    A quick article content teaches you the most important cogs and wheels on nike and things you ought to do immediately. [url=http://www.mizunogoruhujp.com/]ミズノ[/url] The Industry secrets For nike [url=http://www.mizunogoruhujp.com/ミズノ-ゴルフクラブ-c-1.html]ミズノ アイアン[/url] Short post teaches you all intricacies for nike as well as things you must do straight away. [url=http://www.mizunogoruhujp.com/ゴルフグローブ-c-33.html]ミズノ グローブ[/url] What everyone else has been doing with regards to mizuno and furthermore what that you might want to complete different. [url=http://www.mizunogoruhujp.com/ゴルフバッグ-c-7.html]ミズノ[/url] Unprejudiced summary presents you with 4 brand new things on mizuno that noone is bringing up. [url=http://www.mizunogoruhu.com/]ミズノ グローブ[/url] 1 particular double sprain on nike [url=http://www.mizunogoruhu.com/ミズノmizuno-クラブ-c-4.html]ミズノ mp[/url] Products and assembly throughout Manhattan - nike actually leaves with no bon voyage [url=http://www.mizunogoruhu.com/ミズノmizuno-アイアン-c-3.html]ミズノ アイアン[/url] Highly effective strategies for nike that can be used starting right now. [url=http://www.mizunogoruhu.com/ミズノmizuno-バッグ-c-5.html]ミズノ[/url] Short study reveals the proven information regarding nike as well as how it might have an affect on your business.

    Reply
  • multiline tooltip displaying does not work

    Posted by aditzabici on 03/20/2006 09:26am

    I ran your code, but it seems that it doesn't work in the way showed in the picture. The \n is displayed like some squares and the text is not moved to the next line. Do you have any idea?

    Reply
  • Modification for compiling succeeded under the VC.net(V7.0)

    Posted by Legacy on 09/29/2003 12:00am

    Originally posted by: Frank Han

    This is a good source, but there is a bit issue in it when 
    
    compile it under VC.net(v70). It always report a compiling
    error that "error C2039: 'm_pToolTip' : is not a member
    of '_AFX_THREAD_STATE' ".

    In fact, it's simple to modify.
    Modefied codes following:

    BOOL CDataTipListCtrl::OnToolTipText(UINT id,
    NMHDR* pNMHDR,
    LRESULT* pResult)
    {
    // I want to implement this in PreSubclassWindow(),
    // but it crashes.
    if(!m_bToolTipCtrlCustomizeDone)
    {
    /*************** bug location *************************
    AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
    CToolTipCtrl *pToolTip = pThreadState->m_pToolTip;
    ******************************************************/

    ////////////// Modification location //////////////
    #if _MSC_VER >= 1300
    CToolTipCtrl* pToolTip = AfxGetModuleState()->m_thread.GetDataNA()->m_pToolTip;
    #else
    _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
    CToolTipCtrl* pToolTip = pThreadState->m_pToolTip;
    #endif
    ////////////////////////////////////////////////////

    ...// else codes

    }

    ...
    ...// else codes
    }

    Reply
  • tooltip in listview

    Posted by Legacy on 09/17/2003 12:00am

    Originally posted by: sansingh

    This works fine with listctrl but what if i want to display the same tooltip in a Listview derived class

    Reply
  • Thnx But dont work in VC.Net

    Posted by Legacy on 07/21/2003 12:00am

    Originally posted by: MAbolghasemi

    Thank you,
    But When I want to compile it in MFC 7.0 (VC.Net), I have this error :

    e:\Internet\DTListDemo\DataTipListCtrl.cpp(125): error C2039: 'm_pToolTip' : is not a member of '_AFX_THREAD_STATE'

    please help me.
    MAbolghasemi@yahoo.com

    Reply
  • Multiline tooltip problem

    Posted by Legacy on 01/21/2002 12:00am

    Originally posted by: Helamonster

    I don't get multiline tooltips.
    
    I get a block character for all carriage returns / line feeds that I have in the string ( '\r', '\n' ).

    It works if I take out the following condition:
    if(!m_bToolTipCtrlCustomizeDone)

    in CDataTipListCtrl::OnToolTipText(...)

    In other words, if I set the max tool tip width to 500 every time the program requests the tool tip text, it works.

    Anybody know a better way of fixing the problem?

    P.S. I do initialize bToolTipCtrlCustomizeDone to false and I am sure that the SetMaxTipWidth function is being called.
    I'm actually using:
    ::SendMessage(pNMHDR->hwndFrom, TTM_SETMAXTIPWIDTH, 0, 500);
    because AFX_THREAD_STATE is not defined

    Thanks for any help

    Reply
  • displaying two tool tip

    Posted by Legacy on 12/18/2001 12:00am

    Originally posted by: chittaranhan

    i have added tool tips to my ListCtrl program containing thumbnails, which is showing the thumb nail name. but some cases it is showing two tool tips( one what i have added and another provided by OS) when the text length is comparatively large(172 pixel).so how to show only one tool tips.
    Please suggest me regarding this.

    Reply
  • Works for top and bottom rows but not for middle row

    Posted by Legacy on 12/12/2001 12:00am

    Originally posted by: Haobin Xu

    My app contains a listview control that has 3 row and 9 column data on it. The code works perfectly for top and bottom row data but it could not display ToolTips for middle row data. Any idea would be greatly appreciated!

    Haobin


    Reply
  • Very good !!!!! I have only one problem

    Posted by Legacy on 12/03/2001 12:00am

    Originally posted by: Volki

    I selected "kein Bildlauf" in the properties
    and the program chrashed. Can you help me.

    Thanks !
    Volki

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • On-demand Event Event Date: October 29, 2014 It's well understood how critical version control is for code. However, its importance to DevOps isn't always recognized. The 2014 DevOps Survey of Practice shows that one of the key predictors of DevOps success is putting all production environment artifacts into version control. In this webcast, Gene Kim discusses these survey findings and shares woeful tales of artifact management gone wrong! Gene also shares examples of how high-performing DevOps …

Most Popular Programming Stories

More for Developers

RSS Feeds