Tooltip ControlsTooltip Controls*
*Contents  *Index  *Topic Contents
*Previous Topic: TBSAVEPARAMS
*Next Topic: Tooltip Control Reference

Tooltip Controls


A tooltip control is a small pop-up window that displays a single line of text that describes the purpose of a tool in an application. A tool is either a window, such as a child window or control, or an application-defined rectangular area within a window's client area.

arrowy.gifAbout Tooltip Controls

arrowy.gifUsing Tooltip Controls

arrowy.gifTooltip Control Update in Internet Explorer

arrowy.gifTooltip Control Reference

About Tooltip Controls

A tooltip control is hidden most of the time, appearing only when the user puts the cursor on a tool and leaves it there for approximately one-half second. The tooltip control appears near the cursor and disappears when the user clicks a mouse button or moves the cursor off of the tool. A single tooltip control can support any number of tools. The following illustration shows a tooltip control associated with a button in a toolbar control.

Tooltip control for a button in a toolbar control.

Tooltip Creation

You create a tooltip control by using the CreateWindowEx function, specifying the TOOLTIPS_CLASS window class. The class is registered when the common control dynamic-link library (DLL) is loaded. To ensure that this DLL is loaded, include the InitCommonControls function in your application.

The window procedure for a tooltip control automatically sets the size, position, and visibility of the tooltip control. The height of the tooltip window is based on the height of the font currently selected into the device context for the tooltip control. The width varies based on the length of the string currently in the tooltip window.

Activation

A tooltip control itself can be either active or inactive. When it is active, the tooltip control appears when the cursor is on a tool. When it is inactive, the tooltip control does not appear, even if the cursor is on a tool. The TTM_ACTIVATE message activates and deactivates a tooltip control.

Types of Tools

A tooltip control can support any number of tools. To support a particular tool, you must register the tool with the tooltip control by sending the control the TTM_ADDTOOL message. The message includes the address of a TOOLINFO structure, which provides information the tooltip control needs to display text for the tool. The cbSize member is required and must specify the size of the structure.

A tooltip control supports tools implemented as windows (such as child windows or control windows) and as rectangular areas within a window's client area. When you add a tool implemented as a rectangular area, the hwnd member of TOOLINFO must specify the handle to the window that contains the area, and the rect member must specify the client coordinates of the area's bounding rectangle. In addition, the uId member must specify the application-defined identifier for the tool.

When you add a tool implemented as a window, the uId member of TOOLINFO must contain the window handle to the tool. Also, the uFlags member must specify the TTF_IDISHWND value, which tells the tooltip control to interpret the uId member as a window handle.

Tool Text

When you add a tool to a tooltip control, the lpszText member of the TOOLINFO structure must specify the address of the string to display for the tool. You can change the text any time after adding the tool by using the TTM_UPDATETIPTEXT message.

If the high-order word of lpszText is zero, the low-order word must be the identifier of a string resource. When the tooltip control needs the text, the system loads the specified string resource from the application instance identified by the hinst member of TOOLINFO.

If you specify the LPSTR_TEXTCALLBACK value in the lpszText member, the tooltip control notifies the window specified in the hwnd member of TOOLINFO whenever the tooltip control needs to display text for the tool. The tooltip control sends the TTN_NEEDTEXT notification message to the window. The message includes the address of a TOOLTIPTEXT structure, which contains the window handle as well as the application-defined identifier for the tool. The window examines the structure to determine the tool for which text is needed, and it fills the appropriate structure members with information that the tooltip control needs to display the string.

Many applications create toolbars containing tools that correspond to menu commands. For such tools, it is convenient for the tooltip control to display the same text as the corresponding menu item. The system automatically strips the ampersand (&) accelerator characters from all strings passed to a tooltip control, unless the control has the TTS_NOPREFIX style.

To retrieve the text for a tool, use the TTM_GETTEXT message.

Relaying Mouse Messages to the Tooltip

A tooltip control needs to receive mouse messages to determine when to display the tooltip window. Because Microsoft® Windows® sends mouse messages only to the window that contains the cursor, you must use the TTM_RELAYEVENT message to relay mouse messages to the tooltip control.

If a tool is implemented as a rectangular area in an application-defined window, the window procedure receives mouse messages and can relay them to the tooltip control. However, if a tool is implemented as a system-defined window, the mouse messages are sent to the window and are not readily available to the application. You must use a message hook to access and relay the mouse messages, or you must subclass the window.

When a tooltip control receives a relayed WM_MOUSEMOVE message, it determines whether the cursor is in the bounding rectangle of a tool. If the cursor is there, the tooltip control sets a timer. At the end of the time-out duration, the tooltip control checks the position of the cursor to see whether it has moved. If it hasn't, the tooltip control retrieves the text for the tool, copies the text into the tooltip window, and shows the window. The tooltip control continues to show the window until it receives a relayed button-up or button-down message or until a relayed WM_MOUSEMOVE message indicates that the cursor has moved outside the bounding rectangle of the tool.

A tooltip control actually has three time-out durations associated with it. The initial duration is the length of time that the cursor must remain stationary within the bounding rectangle of a tool before the tooltip window is displayed. The reshow duration is the length of the delay before subsequent tooltip windows are displayed when the cursor moves from one tool to another. The pop-up duration is the length of time that the tooltip window remains displayed before it is hidden. That is, if the cursor remains stationary within the bounding rectangle after the tooltip window is displayed, the tooltip window is automatically hidden at the end of the pop-up duration. You can adjust all of the time-out durations by using the TTM_SETDELAYTIME message.

If an application includes a tool implemented as a rectangular area and the size or position of the control changes, it can use the TTM_NEWTOOLRECT message to report the change to the tooltip control. An application does not need to report size and position changes for a tool implemented as a window. This is because the tooltip control uses the window handle of a tool to determine if the cursor is on the tool, not the tool's bounding rectangle.

When it is about to be displayed, a tooltip control sends the TTN_SHOW notification to the owner window. A tooltip control sends the TTN_POP notification when it is about to be hidden. Each notification is sent in the context of a WM_NOTIFY message.

Tooltip Hit Testing

The TTM_HITTEST message allows you to retrieve information that a tooltip control maintains about the tool occupying a particular point. The message includes a TTHITTESTINFO structure that contains a window handle, the coordinates of a point, and the address of a TOOLINFO structure. The tooltip control determines whether a tool occupies the point and, if it does, fills TOOLINFO with information about the tool.

Miscellaneous Messages

The TTM_GETCURRENTTOOL and TTM_GETTOOLINFO messages fill a TOOLINFO structure with information about a tool that has been registered with a tooltip control. The TTM_SETTOOLINFO message allows you to change the information that a tooltip control maintains for a particular tool. The TTM_DELTOOL message deletes a tool from a tooltip control.

Default Tooltip Control Message Processing

This section describes the messages handled by the window procedure for the TOOLTIPS_CLASS window class.
Message Default processing
WM_CREATE Ensures that the tooltip control has the WS_EX_TOOLWINDOW and WS_POPUP window styles. It also allocates memory and initializes internal variables.
WM_DESTROY Frees resources allocated for the tooltip control.
WM_GETFONT Returns the handle of the font that the tooltip control will use to draw text.
WM_MOUSEMOVE Hides the tooltip window.
WM_PAINT Draws the tooltip window.
WM_SETFONT Sets the handle of the font that the tooltip control will use to draw text.
WM_TIMER Hides the tooltip window if the tool has changed position or if the cursor has moved outside the tool. Otherwise, it shows the tooltip window.
WM_WININICHANGE Resets internal variables that are based on system metrics.

Using Tooltip Controls

This section provides examples that demonstrate how to create a tooltip control and use a tooltip control with a dialog box.

Creating a Tooltip Control

The following example demonstrates how to create a tooltip control and add several tools to it. The example creates a grid of rectangles in the client area of a window and then uses the TTM_ADDTOOL message to add each rectangle to the tooltip control. Note that the window procedure for the owner of the tooltip control must handle mouse messages and pass them on to the tooltip control by using the TTM_RELAYEVENT message.

	// DoCreateTooltip - creates a tooltip control and adds some tools 
	//     to it. 
	// Returns the handle of the tooltip control if successful, or NULL
	//     otherwise. 
	// hwndOwner - handle of the owner window. 
	// 
	// Global variable 
	//     g_hinst - handle of the application instance. 
	extern HINSTANCE g_hinst; 
 
	HWND DoCreateTooltip(HWND hwndOwner) 
	{ 
    HWND hwndTT;    // handle of tooltip 
    int row, col;   // rows and columns 
    TOOLINFO ti;    // tool information 
    int id = 0;     // offset to string identifiers 
    static char *szTips[NUM_TIPS] =   // tip text 
    { 
    "Cut", "Copy", "Paste", "Undo", "Open", "Save" 
    }; 
 
    // Ensure that the common control DLL is loaded, and create 
    // a tooltip control. 
    InitCommonControls(); 
 
    hwndTT = CreateWindow(TOOLTIPS_CLASS, (LPSTR) NULL, TTS_ALWAYSTIP, 
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 
        NULL, (HMENU) NULL, g_hinst, NULL); 
 
    if (hwndTT == (HWND) NULL) 
        return (HWND) NULL; 
 
    // Divide the client area into a grid of rectangles, and add each 
    // rectangle to the tooltip. 
    for (row = 0; row < MAX_ROWS ; row++ ) 
        for (col = 0; col < MAX_COLS; col++) { 
            ti.cbSize = sizeof(TOOLINFO); 
            ti.uFlags = 0; 
            ti.hwnd = hwndOwner; 
            ti.hinst = g_hinst; 
            ti.uId = (UINT) id; 
            ti.lpszText = (LPSTR) szTips[id++]; 
            ti.rect.left = col * CX_COLUMN; 
            ti.rect.top = row * CY_ROW; 
            ti.rect.right = ti.rect.left + CX_COLUMN; 
            ti.rect.bottom = ti.rect.top + CY_ROW; 
 
            if (!SendMessage(hwndTT, TTM_ADDTOOL, 0, 
                    (LPARAM) (LPTOOLINFO) &ti)) 
                return NULL; 
        } 
 
    return hwndTT; 
	} 
 

Using a Tooltip Control with a Dialog Box

The following example includes a set of application-defined functions that implement a tooltip control for a dialog box. The DoCreateDialogTooltip function creates a tooltip control and uses the EnumChildWindows function to enumerate the controls in the dialog box. The enumeration procedure, EnumChildProc, registers each control with the tooltip control. The procedure specifies the dialog box as the parent window of each tooltip control and includes the LPSTR_TEXTCALLBACK value for each tooltip control. As a result, the dialog box receives a WM_NOTIFY message that contains the TTN_NEEDTEXT notification message whenever the tooltip control needs the text for a control. The dialog box procedure calls the OnWMNotify function to process the TTN_NEEDTEXT notifications. OnWMNotify provides the appropriate string based on the identifier of the tooltip control.

The tooltip control needs to receive mouse messages that the system sends to the control windows. To access the messages, the DoCreateDialogTooltip function installs a hook procedure of the WH_GETMESSAGE type. The hook procedure, GetMsgProc, monitors the message stream for mouse messages intended for one of the control windows and relays the messages to the tooltip control.

	// DoCreateDialogTooltip - creates a tooltip control for a dialog box, 
	//     enumerates the child control windows, and installs a hook 
	//     procedure to monitor the message stream for mouse messages posted 
	//     to the control windows. 
	// Returns TRUE if successful, or FALSE otherwise. 
	// 
	// Global variables 
	// g_hinst - handle to the application instance. 
	// g_hwndTT - handle to the tooltip control. 
	// g_hwndDlg - handle to the dialog box. 
	// g_hhk - handle to the hook procedure. 
 
	BOOL DoCreateDialogTooltip(void) 
	{ 
 
    // Ensure that the common control DLL is loaded, and create 
    // a tooltip control. 
    InitCommonControls(); 
    g_hwndTT = CreateWindowEx(0, TOOLTIPS_CLASS, (LPSTR) NULL, 
        TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 
        CW_USEDEFAULT, g_hwndDlg, (HMENU) NULL, g_hinst, NULL); 
 
    if (g_hwndTT == NULL) 
        return FALSE; 
 
    // Enumerate the child windows to register them with the tooltip
    // control. 
    if (!EnumChildWindows(g_hwndDlg, (WNDENUMPROC) EnumChildProc, 0)) 
        return FALSE; 
 
    // Install a hook procedure to monitor the message stream for mouse 
    // messages intended for the controls in the dialog box. 
    g_hhk = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, 
        (HINSTANCE) NULL, GetCurrentThreadId()); 
 
    if (g_hhk == (HHOOK) NULL) 
        return FALSE; 
 
    return TRUE; 
	} 
 
	// EmumChildProc - registers control windows with a tooltip control by
	//     using the TTM_ADDTOOL message to pass the address of a 
	//     TOOLINFO structure. 
	// Returns TRUE if successful, or FALSE otherwise. 
	// hwndCtrl - handle of a control window. 
	// lParam - application-defined value (not used). 
	BOOL EnumChildProc(HWND hwndCtrl, LPARAM lParam) 
	{ 
    TOOLINFO ti; 
    char szClass[64]; 
 
    // Skip static controls. 
    GetClassName(hwndCtrl, szClass, sizeof(szClass)); 
    if (lstrcmpi(szClass, "STATIC") { 
        ti.cbSize = sizeof(TOOLINFO); 
        ti.uFlags = TTF_IDISHWND; 
        ti.hwnd = g_hwndDlg; 
        ti.uId = (UINT) hwndCtrl; 
        ti.hinst = 0; 
        ti.lpszText = LPSTR_TEXTCALLBACK; 
        SendMessage(g_hwndTT, TTM_ADDTOOL, 0, 
            (LPARAM) (LPTOOLINFO) &ti); 
    } 
    return TRUE; 
	} 
 
	// GetMsgProc - monitors the message stream for mouse messages intended 
	//     for a control window in the dialog box. 
	// Returns a message-dependent value. 
	// nCode - hook code. 
	// wParam - message flag (not used). 
	// lParam - address of an MSG structure. 
	LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam) 
	{ 
    MSG *lpmsg; 
 
    lpmsg = (MSG *) lParam; 
    if (nCode < 0 || !(IsChild(g_hwndDlg, lpmsg->hwnd))) 
        return (CallNextHookEx(g_hhk, nCode, wParam, lParam)); 
 
    switch (lpmsg->message) { 
        case WM_MOUSEMOVE: 
        case WM_LBUTTONDOWN: 
        case WM_LBUTTONUP: 
        case WM_RBUTTONDOWN: 
        case WM_RBUTTONUP: 
            if (g_hwndTT != NULL) { 
                MSG msg; 
 
                msg.lParam = lpmsg->lParam; 
                msg.wParam = lpmsg->wParam; 
                msg.message = lpmsg->message; 
                msg.hwnd = hwnd; 
                SendMessage(g_hwndTT, TTM_RELAYEVENT, 0, 
                    (LPARAM) (LPMSG) &msg); 
            } 
            break; 
        default: 
            break; 
    } 
    return (CallNextHookEx(g_hhk, nCode, wParam, lParam)); 
	} 
 
	// OnWMNotify - provides the tooltip control with the appropriate text 
	//     to display for a control window. This function is called by 
	//     the dialog box procedure in response to a WM_NOTIFY message. 
	// lParam - second message parameter of the WM_NOTIFY message. 
	VOID OnWMNotify(LPARAM lParam) 
	{ 
    LPTOOLTIPTEXT lpttt; 
    int idCtrl; 
 
    if ((((LPNMHDR) lParam)->code) == TTN_NEEDTEXT) { 
        idCtrl = GetDlgCtrlID((HWND) ((LPNMHDR) lParam)->idFrom); 
        lpttt = (LPTOOLTIPTEXT) lParam; 
 
        switch (idCtrl) { 
            case ID_HORZSCROLL: 
                lpttt->lpszText = "A horizontal scroll bar."; 
                return; 
 
            case ID_CHECK: 
                lpttt->lpszText = "A check box."; 
                return; 
 
            case ID_EDIT: 
                lpttt->lpszText = "An edit control."; 
                return; 
        } 
    } 
	return; 
	} 
 

Tooltip Control Update in Internet Explorer

Tooltip controls in Microsoft® Internet Explorer support a new feature called a tracking tooltip.

Tracking Tooltips

Tooltip controls support tracking tooltips, which are tooltip windows that you can dynamically position on the screen. By rapidly updating the position, the tooltip window appears to move smoothly, or "track." This functionality can be useful if you need tooltip text to follow the position of the pointer as it moves.

To create a tracking tooltip, use the TTM_ADDTOOL message, including the TTF_TRACK flag in the uFlags member of the accompanying TOOLINFO structure.

Your application must manually activate and deactivate a tracking tooltip using the TTM_TRACKACTIVATE message. While your tooltip is active, your application must supply the location at which the tooltip window will appear by using the TTM_TRACKPOSITION message. Tracking tooltip controls do not support the TTF_SUBCLASS style, so all mouse events must be forwarded from the parent to the child using TTM_RELAYEVENT messages.

The TTM_TRACKPOSITION message causes the tooltip control to display the window using one of two placement styles:

For more information and implementation details, see Creating Tracking Tooltips and Supporting Tracking Tooltips.

Creating Tracking Tooltips

The following example demonstrates how to create a tooltip control and assign a tool to it. The example specifies the main window's entire client area as the tool, but you could specify distinct portions of the client area or specify a different window altogether.

The example uses the TTM_ADDTOOL message to add the tool to the tooltip control. Tracking tooltips do not support the TTF_SUBCLASS flag, so the control's owner must manually forward pertinent messages (like WM_MOUSEMOVE) by using TTM_RELAYEVENT.

Additionally, the uFlags member of the TOOLINFO structure used in the example includes the TTF_ABSOLUTE flag. This flag causes the tooltip control to display tooltip text at the exact coordinates the application provides when it sends the TTM_TRACKPOSITION message. Without the TTF_ABSOLUTE flag, the tooltip control will choose a location to display the tooltip text based on the coordinates you provide. This causes tooltip text to appear next to the corresponding tool but not necessarily at the exact coordinates the application provided.

For additional information on using the TTM_TRACKPOSITION message, see Supporting Tracking Tooltips.

HWND WINAPI CreateTT(HWND hwndOwner)
{
    INITCOMMONCONTROLSEX icex;
    HWND        hwndTT;
    TOOLINFO    ti;

    // Load the tooltips class from the DLL.
    icex.dwSize = sizeof(icex);
    icex.dwICC  = ICC_BAR_CLASSES;

    if(!InitCommonControlsEx(&icex))
       return NULL;

    // Create the tooltip control.
    hwndTT = CreateWindow(TOOLTIPS_CLASS, TEXT(""),
                          WS_POPUP,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, (HMENU)NULL, g_hinst,
                          NULL);

    // Prep the TOOLINFO structure to be used for a tracking tooltip.
    ti.cbSize = sizeof(TOOLINFO);
    ti.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;
    ti.hwnd   = hwndOwner;
    ti.uId    = (UINT)g_hwndMain;
    ti.hinst  = g_hinst;
    ti.lpszText  = LPSTR_TEXTCALLBACK;
    ti.rect.left = ti.rect.top = ti.rect.bottom = ti.rect.right = 0; 
    
    // Add the tool to the control, displaying an error if needed.
    if(!SendMessage(hwndTT,TTM_ADDTOOL,0,(LPARAM)&ti)){
        MessageBox(hwndOwner,"Couldn't create the tooltip control.","Error",MB_OK);
        return NULL;
    }
    
    // Activate (display) the tracking tooltip.  Then, set a global
    // flag value to indicate that the tooltip is active, so other
    // functions can check to see if it's visible.
    SendMessage(hwndTT,TTM_TRACKACTIVATE,(WPARAM)TRUE,(LPARAM)&ti);
    g_bIsVisible = TRUE;

    return(hwndTT);    
}

Supporting Tracking Tooltips

The following example is a simple window process function that supports tracking tooltips. It requests the current position of the pointer using the GetCursorPos function and then adds 15 pixels to the x- and y-coordinates so the tooltip appears slightly below and to the right of the pointer.

Note that the example relies on the value of a global variable, g_bIsVisible, to determine whether the application should send the TTM_TRACKPOSITION message. For the purpose of this example, g_bIsVisible is a BOOL variable that another function sets to TRUE upon sending the TTM_TRACKACTIVATE message to activate the tooltip. This way, if the tooltip is inactive, the additional overhead to calculate and send a message is not incurred.

LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    HDC   hdc;
    PAINTSTRUCT ps;
    MSG   mssg;
    POINT pt;

    switch(msg){
        case WM_MOUSEMOVE:
            if(g_bIsVisible){
                mssg.hwnd    = g_hwndMain;
                mssg.message = msg;
                mssg.wParam  = wParam;
                mssg.lParam  = lParam;

                GetCursorPos(&pt);
                mssg.pt.x    = pt.x;
                mssg.pt.y    = pt.y;

#define X_OFFSET 15
#define Y_OFFSET X_OFFSET
                SendMessage(g_hwndTT,
                            TTM_TRACKPOSITION,0,
                            (LPARAM)MAKELPARAM(pt.x+X_OFFSET,
                            pt.y+Y_OFFSET));
            }
            break;

/*
 *
 *  Other standard window messages can be handled here.
 *
 */
    }
    return 0;
}

Up Top of Page
© 1997 Microsoft Corporation. All rights reserved. Terms of Use.