winapitrackbarcommon-controlscustom-draw

Custom trackbar ticks


I'm using the stock Trackbar control. I would like to custom draw the ticks.

Here I made an experiment, just trying to draw in the right place:

case WM_NOTIFY:
{
    NMHDR* nMhdr = (NMHDR*) lParam;
    NMCUSTOMDRAW* nMcd = (NMCUSTOMDRAW*) lParam;

    if (nMhdr->code == NM_CUSTOMDRAW)
    {
        switch (nMcd->dwDrawStage)
        {
            case CDDS_PREPAINT:
            {
                return CDRF_NOTIFYITEMDRAW;
            }

            case CDDS_ITEMPREPAINT:
            {
                if (nMcd->dwItemSpec == TBCD_TICS)
                {
                    FillRect(nMcd->hdc, &nMcd->rc, (HBRUSH) GetStockObject(BLACK_BRUSH));

                    return CDRF_SKIPDEFAULT;
                }
                else
                {
                    return CDRF_DODEFAULT;
                }

                break;
            }

            default:
            {
                result = CDRF_DODEFAULT;

                break;
            }
        }
    }

    break;
}

In my CDDS_ITEMPREPAINT, if dwItemSpec == TBCD_TICS, then the update rect (NMCUSTOMDRAW->rc) is always an empty rect. I checked, and for the other items (TBCD_CHANNEL and TBCD_THUMB), I get a valid rect and can draw in place of the channel and thumb.

Ok: so what's the point of TBCD_TICS if it doesn't give me a rect to draw in?

So maybe I can get the tick positions another way. Well, there's TBM_GETTICPOS, which seems like it would work. Except the documentation mentions this:

The positions of the first and last tick marks are not directly available via this message.

So how can I get the first and last tick positions? They do not correspond with the start and end of the channel, the ticks are inset slightly. Perhaps we can calculate the insert from the sides of the channel, but that seems fragile (especially on differently scaled displays).


Solution

  • So how can I get the first and last tick positions?

    The old method (XP and older) to get them seems to still work (I just tested on Windows 10) :

        RECT rectTrackbar;
        GetClientRect(hWndTB, &rectTrackbar);
        RECT rectThumb;
        SendMessage(hWndTB, TBM_GETTHUMBRECT, 0, (LPARAM)&rectThumb);
        int nThumbWidth = rectThumb.right - rectThumb.left;
        int nXTicFirst = rectTrackbar.left += (nThumbWidth + 2);
        int nXTicLast = rectTrackbar.right -= (nThumbWidth + 2 + 1);