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

  • On-demand Event Event Date: September 10, 2014 Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild." This loop of continuous delivery and continuous feedback is how the best mobile …

  • Java developers know that testing code changes can be a huge pain, and waiting for an application to redeploy after a code fix can take an eternity. Wouldn't it be great if you could see your code changes immediately, fine-tune, debug, explore and deploy code without waiting for ages? In this white paper, find out how that's possible with a Java plugin that drastically changes the way you develop, test and run Java applications. Discover the advantages of this plugin, and the changes you can expect to see …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds