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

  • 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 …

  • On-demand Event Event Date: December 18, 2014 The Internet of Things (IoT) incorporates physical devices into business processes using predictive analytics. While it relies heavily on existing Internet technologies, it differs by including physical devices, specialized protocols, physical analytics, and a unique partner network. To capture the real business value of IoT, the industry must move beyond customized projects to general patterns and platforms. Check out this webcast and join industry experts as …

Most Popular Programming Stories

More for Developers

RSS Feeds