October 16th, 2003

Scrollbars redux: Part 12

Reader Jeff Miller added Word-style scroll tips to our sample scrollbar program. Here’s how he did it:

HWND g_hwndTT;              /* tooltip control */
TOOLINFO g_ti;              /* tooltip info struct */
BOOL g_fInScroll;           /* Scroll state */
void CancelScrollTip()
{
    if (g_fInScroll) {
        g_fInScroll = FALSE;
        SendMessage(g_hwndTT, TTM_TRACKACTIVATE,
                    FALSE, (LPARAM)&g_ti);
    }
}
void UpdateScrollTip()
{
    if (!g_hwndTT) return;
    if (!g_fInScroll) {
        g_fInScroll = TRUE;
        DWORD dwPos = GetMessagePos();
        SendMessage(g_hwndTT, TTM_TRACKPOSITION, 0,
                    MAKELPARAM(GET_X_LPARAM(dwPos) +
                               GetSystemMetrics(SM_CXVSCROLL)
                               GET_Y_LPARAM(dwPos)));
        SendMessage(g_hwndTT, TTM_TRACKACTIVATE, TRUE,
                    (LPARAM)&g_ti);
    }
    // Reset the text to LPSTR_TEXTCALLBACK so it will get
    // re-fetched
    SendMessage(g_hwndTT, TTM_SETTOOLINFO, 0,
                (LPARAM)&g_ti);
}
LRESULT
OnNotify(HWND hwnd, int id, LPNMHDR pnm)
{
    switch (pnm->code) {
    case TTN_GETDISPINFO:
        {
            NMTTDISPINFO *pnmtdi = (NMTTDISPINFO*)pnm;
            wnsprintf(pnmtdi->lpszText, 80,
                      TEXT("Line: %d"), g_yOrigin);
        }
        break;
    }
    return 0;
}
// change case statement in OnVscroll:
    case SB_THUMBTRACK:     ScrollTo(hwnd, GetTrackPos(hwnd, SB_VERT));
                            UpdateScrollTip(); break;
// add case statement to OnVscroll:
    case SB_ENDSCROLL:      CancelScrollTip(); break;
// add to OnCreate
    /* Create and initialize the tooltip */
    g_hwndTT = CreateWindow(TOOLTIPS_CLASS, NULL,
             WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
             CW_USEDEFAULT, CW_USEDEFAULT,
             CW_USEDEFAULT, CW_USEDEFAULT,
             hwnd, NULL, NULL, NULL);
    if (g_hwndTT) {
        g_ti.cbSize = sizeof(g_ti);
        g_ti.uFlags = TTF_TRACK;
        g_ti.hwnd = hwnd;
        g_ti.lpszText = LPSTR_TEXTCALLBACK;
        SendMessage(g_hwndTT, TTM_ADDTOOL, 0, (LPARAM)&g_ti);
    }
// add to WndProc
    case WM_NOTIFY: return OnNotify(hwnd, (int)wParam,
                                    (LPNMHDR)lParam);

A tracking tooltip is used to display the scroll tip because we don’t want the tooltip to do automatic positioning or automatic show/hide.

When a tracking scroll occurs (SB_THUMBTRACK), we update the scroll tip, displaying it if necessary. When the tracking scroll ends (SB_ENDSCROLL), we remove the tip.

The above code mimics the Word XP style, where the tooltip appears near the original thumb position but does not follow the thumb as the user scrolls. If you prefer that the tooltip follow the thumb, remove the if (!g_fInScroll) test from the UpdateScrollTip function.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

0 comments

Discussion are closed.