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

  • Packaged application development teams frequently operate with limited testing environments due to time and labor constraints. By virtualizing the entire application stack, packaged application development teams can deliver business results faster, at higher quality, and with lower risk.

  • As mobile devices have pushed their way into the enterprise, they have brought cloud apps along with them. This app explosion means account passwords are multiplying, which exposes corporate data and leads to help desk calls from frustrated users. This paper will discover how IT can improve user productivity, gain visibility and control over SaaS and mobile apps, and stop password sprawl. Download this white paper to learn: How you can leverage your existing AD to manage app access. Key capabilities to …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds