Parent-Independent ToolTip Support for Static (or any) Controls

I have come across many problems related to handling ToolTips in controls without parent involvement. Many samples show how to use ToolTips in a dialog by creating CToolTipCtrl, enabling it, and adding tools. Although it helps, it may turn out that achieving additional functionality proves to be difficult; for example: displaying different text for the same control or displaying information based on area in a window (rectangle). Implementing ToolTips proves to be more difficult for static controls created by inserting the control in a dialog template as well as those that are dynamically created. That is a main reason I have concentrated on the Static control.

All MFC CWnd-derived classes have automatic ToolTips built in. It is just a matter of enabling the tools and properly handling ToolTip messages. This approach may be used on any control, and any child window for that matter, for which we need to handle ToolTips independently of the parent window.

I have written a class that demonstrates ToolTip handling, derived from CStatic, called CStaticTTPSupport; the name is a little long, but serves the purpose. You should treat this class as a boilerplate and change code handling text assignment logic as well as determine a hit value, tailoring it to your needs.

A CWnd implementation of PreTranslateMessage filters messages that are needed for built-in ToolTips by calling FilterToolTipMessage. This in turn calls a virtual override of OnToolHitTest. A default implementation returns -1 if the window does not have children or if the window has ID_STATIC (-1). To change this behavior, the function must be overridden.

int CStaticTTPSupport::OnToolHitTest(CPoint point, TOOLINFO *pTI) const
   pTI->hwnd = m_hWnd;
   pTI->uFlags = 0;                       // we need to differ tools
                                          // by ID, not window handle
   pTI->lpszText = LPSTR_TEXTCALLBACK;    // tell ToolTips to send
                                          // TTN_NEEDTEXT

   for(int iIndx = 0; iIndx < _ZONE_COUNT * 2; iIndx++)
         // point is in this rectangle.
         pTI->rect = m_rectZone[iIndx];
         // TTN_NEEDTEXT Message will use this ID to fill NMHDR structure
         pTI->uId = iIndx;

   return iIndx;    // return index of rectangle

This function sets the TOOLINFO structure that is used by FilterToolTipMessage. The hwnd member is set to the control's handle. It is important because this indicates the window that will receive TTN_NEEDTEXT notification because the lpszText member is initialized with LPSTR_TEXTCALLBACK. See code comments next to the member initialization.

In a nutshell: If the function returns value greater that -1, FilterToolTipMessage will determine the course of action that may show a new popup if needed and kill the old tool. If the hit's value is -1, the ToolTip window is deactivated.

After setting tool information, you need a handler for TTN_NEEDTEXT notification.

  • The notification message handler will always handle TTN_NEEDTEXT notification messages sent exclusively to a control; the control does not have any children. You do not need to indicate whether or not the message was handled; therefore, the ON_NOTIFY_EX macro is not needed.
  • The ToolTip ID is always 0; therefore, the ON_NOTIFY_RANGE macro is not needed.

That is why I used the ON_NOTIFY macro to handle TTN_NEEDTEXT in this particular scenario. In other cases, it may be necessary using the macros that I mentioned above. Mapping macros look as follows:


As you can see, I have mapped two versions of the TTN_NEEDTEXT notification code: ANSI and UNICODE. That may look as though it is unnecessary because the application that is built is not UNICODE. The real reason for handling both is not because the application may be built as UNICODE; it is a ToolTip control that, in newer versions of ComCtl32, have controls built for UNICODE and you may receive UNICODE. For the same reason, the TTN_NEEDTEXT handler handles ANSI and UNICODE versions.

In a sample class that you may have tuned to your needs, I have decided to assign different ToolTip text based on the cursor position over different areas of the window. The client area was divided into 16 rectangles in two rows and eight columns. ToolTip text is set depending on the cursor position over a given rectangle. This is determined in OnToolHitTest, where the hit value is assigned to a TOOLINFO structure.

The sample dialog uses three static controls: the first from a template, subclasses using class wizard; the second that is created and placed in dialog; and the third from a template subclassed without a wizard. The last one demonstrates how to subclass an already existing control by using its window handle, without regard to the control's ID value (IDC_STATIC is used.)

Additional Information

TTN_NEEDTEXT notification was superseded with TTN_GETDISPINFO and TOOLTIPTEXT superseded with NMTTDISPINFO. For benefit of all programmers who use an older SDK and/or VS versions, I decided to use older definitions. This does not break anything because TTN_NEEDTEXT is defined as TTN_GETDISPINFO and TOOLTIPTEXT structure is defined as NMTTDISPINFO for newer releases.

About the Author

John Z. Czopowik VC++ MVP

Microsoft VC++ MVP



  • Nice

    Posted by kirants on 02/28/2005 12:01pm

    Well written and very useful piece of information explained neatly.

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

Top White Papers and Webcasts

  • Today there's no such thing as "one size fits all" when it comes to enterprise mobile computing for field services workers. While the business benefits of automation are clear (e.g. decreased downtime, increased customer satisfaction), selecting the right mobile device mix for the job is becoming more complex. This whitepaper examines 3 challenges organizations face when considering a mobile device deployment for field teams: Integrating new mobile devices with legacy technology Adapting to multi-generational …

  • Featuring Art Schoeller, VP and Principal Analyst, at Forrester Research Live Event Date: November 9, 2016 @ 10 AM PT / 1 PM ET Being "proactive" with your customers is not enough to survive in the market today. The truth is, organizations that understand how to engage customers on their preferred channels will create contextual, and relevant experiences for customers. Plus, they will see the financial impact of nurturing long-term customer loyalty. Join our guest speaker Art Schoeller, VP and Principal …

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date