How to display tooltips for a toolbar in a dialog

It is relatively easy to place a toolbar in a dialog box, but I had a hard time making the tooltips appear since none of the TTN_xxxx message handlers are present in a CDialog derived class. This article describes a simple technique for getting tooltips when you have a toolbar in a dialog. It also gives a brief overview of the steps involved in adding a toolbar to a dialog box.

Step 1

In the dialog's header file you must add a CToolBar instance and an entry in the message map to handle the tooltip messages.

protected:
     CToolBar cToolBar;

at the bottom of the wizard generated message map entries add:

//}}AFX_MSG
afx_msg BOOL OnToolTipText(UINT nID, NMHDR* pNMHDR, LRESULT* pResult);
DECLARE_MESSAGE_MAP()

Step 2

In dialog's implementation file add the following to the end of OnInitDialog to show the toolbar.

//add the tool bar to the dialog
cToolBar.Create(this);
cToolBar.LoadToolBar(IDR_TOOLBAR);
cToolBar.ShowWindow(SW_SHOW);
cToolBar.SetBarStyle(CBRS_ALIGN_TOP | CBRS_TOOLTIPS | CBRS_FLYBY);
RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0);

At the bottom of the message map add the following:

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

Finally add the message handler method as entered in the message map:

BOOL CToolBarTipTestDialog::OnToolTipText(UINT, NMHDR* pNMHDR, LRESULT* pResult)
{
     ASSERT(pNMHDR->code == TTN_NEEDTEXTA || pNMHDR->code == TTN_NEEDTEXTW);

     // if there is a top level routing frame then let it handle the message
     if (GetRoutingFrame() != NULL) return FALSE;

     // to be thorough we will need to handle UNICODE versions of the message also !!
     TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
     TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
     TCHAR szFullText[512];
     CString strTipText;
     UINT nID = pNMHDR->idFrom;

     if (pNMHDR->code == TTN_NEEDTEXTA && (pTTTA->uFlags & TTF_IDISHWND) ||
         pNMHDR->code == TTN_NEEDTEXTW && (pTTTW->uFlags & TTF_IDISHWND))
     {
          // idFrom is actually the HWND of the tool
          nID = ::GetDlgCtrlID((HWND)nID);
     }

     if (nID != 0) // will be zero on a separator
     {
          AfxLoadString(nID, szFullText);
          strTipText=szFullText;

#ifndef _UNICODE
          if (pNMHDR->code == TTN_NEEDTEXTA)
          {
               lstrcpyn(pTTTA->szText, strTipText, sizeof(pTTTA->szText));
          }
          else
          {
               _mbstowcsz(pTTTW->szText, strTipText, sizeof(pTTTW->szText));
          }
#else
          if (pNMHDR->code == TTN_NEEDTEXTA)
          {
               _wcstombsz(pTTTA->szText, strTipText,sizeof(pTTTA->szText));
          }
          else
          {
               lstrcpyn(pTTTW->szText, strTipText, sizeof(pTTTW->szText));
          }
#endif

          *pResult = 0;

          // bring the tooltip window above other popup windows
          ::SetWindowPos(pNMHDR->hwndFrom, HWND_TOP, 0, 0, 0, 0,SWP_NOACTIVATE|
               SWP_NOSIZE|SWP_NOMOVE|SWP_NOOWNERZORDER); return TRUE;
     }
}



Comments

  • Great!

    Posted by HITer Du on 05/29/2013 12:49am

    Great!It successfully solves my problem,and works well in my project!

    Reply
  • Wow it works!

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

    Originally posted by: TK

    Thanks!

    Reply
  • good work

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

    Originally posted by: shijie xiong

    This help me much! thanks

    Reply
  • Simple and Works

    Posted by Legacy on 08/04/2003 12:00am

    Originally posted by: Antoni Masso Mola

    Good Job!

    Reply
  • How to Hook TTN_NEEDTEXT?

    Posted by Legacy on 04/28/2003 12:00am

    Originally posted by: Zhang

    I want to Hook TTN_NEEDTEXTA or TTN_NEEDTEXTW, and change the tooltip string dynamicly. I used SetWindowsHookEx( WH_CALLWNDPROC, Hook_ToolbarTip, NULL, GetCurrentThreadId()) to hook the WM_NOTIFY message, I get it, then from the code I found the TTN_NEEDTEXTW message, the code I wrote in the Hook_ToolbarTip was that:
    
    LRESULT CALLBACK Hook_ToolbarTip(int code, WPARAM wParam, LPARAM lParam)
    {
    CWPSTRUCT* pTemp = (CWPSTRUCT*)lParam;
    if(code == HC_ACTION )
    {
    HWND hWnd = pTemp->hwnd;
    if( pTemp->message == WM_NOTIFY )
    {
    if( ((LPNMHDR)(pTemp->lParam))->code == TTN_NEEDTEXTA || ((LPNMHDR)(pTemp->lParam))->code == TTN_NEEDTEXTW )
    {
    NMHDR* pNMHDR = (NMHDR*)(pTemp->lParam);
    TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
    TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
    CString strTipText = "hehe";
    #ifndef _UNICODE
    if (pNMHDR->code == TTN_NEEDTEXTA)
    lstrcpyn(pTTTA->szText, strTipText, _countof(pTTTA->szText));
    else
    _mbstowcsz(pTTTW->szText, strTipText, _countof(pTTTW->szText));
    #else
    if (pNMHDR->code == TTN_NEEDTEXTA)
    _wcstombsz(pTTTA->szText, strTipText, _countof(pTTTA->szText));
    else
    lstrcpyn(pTTTW->szText, strTipText, _countof(pTTTW->szText));
    #endif
    }
    }
    return CallNextHookEx( g_Hook, code, wParam, lParam);
    }
    But the tooltip text didn't change. What's the matter? How can I do, if I want to hook the massage, and change the text dynamicly? thank you.

    Reply
  • A better OnToolTipText, the one in this article is bugged

    Posted by Legacy on 04/15/2003 12:00am

    Originally posted by: Wilhelm Svenselius

    BOOL CMainDlg::OnToolTipText( UINT, NMHDR* pNMHDR, LRESULT* pResult )
    
    {
    if( pNMHDR->code == TTN_NEEDTEXTW )
    {
    TOOLTIPTEXTW* pTTTW = reinterpret_cast<TOOLTIPTEXTW*>( pNMHDR );
    UINT nID = static_cast<UINT>( pNMHDR->idFrom );

    if( pTTTW->uFlags & TTF_IDISHWND )
    nID = ::GetDlgCtrlID( (HWND) nID );

    if( nID != 0 )
    {
    CString strTipText;
    strTipText.LoadString( nID );
    wcscpy( pTTTW->szText, CT2W( strTipText ) );
    ::SetWindowPos( pNMHDR->hwndFrom, HWND_TOP, 0, 0, 0, 0,SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER );
    }
    }
    else
    {
    TOOLTIPTEXTA* pTTTA = reinterpret_cast<TOOLTIPTEXTA*>( pNMHDR );
    UINT nID = static_cast<UINT>( pNMHDR->idFrom );

    if( pTTTA->uFlags & TTF_IDISHWND )
    nID = ::GetDlgCtrlID( (HWND) nID );

    if( nID != 0 )
    {
    CString strTipText;
    strTipText.LoadString( nID );
    strcpy( pTTTA->szText, CT2A( strTipText ) );
    ::SetWindowPos( pNMHDR->hwndFrom, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER );
    }
    }

    *pResult = 0;
    return TRUE;
    }

    Reply
  • Thanks a Bundle!

    Posted by Legacy on 12/19/2002 12:00am

    Originally posted by: Paul

    Fantastic work! Saved me a bundle of time.

    This is the beauty of the Internet - knowledge transfer.

    Reply
  • I 服了you!

    Posted by Legacy on 11/18/2002 12:00am

    Originally posted by: jack

    Great work!

    Reply
  • it's very fine

    Posted by Legacy on 09/10/2002 12:00am

    Originally posted by: Marek Nadrowski

    Thank you. I need that. I am changing AfxLoadString for
    LoadString(NULL,nID,szFullText,TEXT_LENGTH);
    and everything it's ok

    Reply
  • Nice works

    Posted by Legacy on 08/13/2002 12:00am

    Originally posted by: Willem

    Well Done, Ive been trying all kinds of tricks but this one did the job.
    

    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 …

  • With the average hard drive now averaging one terabyte in size, the fallout from the explosion of user-created data has become an overwhelming volume of potential evidence that law-enforcement and corporate investigators spend countless hours examining. Join Us and SANS' Rob Lee for our 45-minute webinar, A Triage and Collection Strategy for Time-Sensitive Investigations, will demonstrate how to: Identify the folders and files that often contain key insights Reduce the time spent sifting through content by …

Most Popular Programming Stories

More for Developers

RSS Feeds