Search code examples
c++winapiownerdrawn

Detect Mouse Hover Over Button?


I have an owner-drawn button that I would like to highlight, when the mouse hovers over it. Here is the simplified code, that doesn't seem to work:

case WM_DRAWITEM:
     LPDRAWITEMSTRUCT  pDraw = (LPDRAWITEMSTRUCT)lParam;
     if(pDraw->itemState == ODS_HOTLIGHT)  DrawButton(pDraw->hDC, HIcolor);
     else                                  DrawButton(pDraw->hDC, normcolor);
     return 0;

DrawButton is a custom function that draws the button. The second parameter of this function is the primary color of the button. The function has no trouble drawing the button. The problem in in detecting the "item state".

I have also tried using if(pDraw->itemState & ODS_HOTLIGHT). That does not work either.

Obviously, I am missing something. In my search, I have come across many answers. However, none of them are in C++.


Solution

  • ODS_HOTLIGHT may not be used by the button. See What states are possible in a DRAWITEMSTRUCT structure?.

    You can use subclassing, and then use TrackMouseEvent to get the event in SUBCLASSPROC.

    LRESULT CALLBACK Subclassproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
    {
        if (uMsg == WM_MOUSEMOVE)
        {
            TRACKMOUSEEVENT ev = {};
            ev.cbSize = sizeof(TRACKMOUSEEVENT);
            ev.dwFlags = TME_HOVER | TME_LEAVE;
            ev.hwndTrack = hWnd;
            ev.dwHoverTime = HOVER_DEFAULT;
            TrackMouseEvent(&ev);
        }
        else if (uMsg == WM_MOUSEHOVER)
        {
            RECT rc = {};
            GetClientRect(hWnd, &rc);
            HDC hdc = GetDC(hWnd);
            SetDCBrushColor(hdc, RGB(255, 0, 0));
    
            SelectObject(hdc, GetStockObject(DC_BRUSH));
    
            RoundRect(hdc, rc.left, rc.top,
                rc.right, rc.bottom, 0, 0);
        }
        else if (uMsg == WM_MOUSELEAVE)
        {
            RECT rc = {};
            GetClientRect(hWnd, &rc);
            HDC hdc = GetDC(hWnd);
            SetDCBrushColor(hdc, RGB(0, 255, 0));
    
            SelectObject(hdc, GetStockObject(DC_BRUSH));
    
            RoundRect(hdc, rc.left, rc.top,
                rc.right, rc.bottom, 0, 0);
            TRACKMOUSEEVENT ev = {};
            ev.cbSize = sizeof(TRACKMOUSEEVENT);
            ev.dwFlags = TME_HOVER | TME_LEAVE | TME_CANCEL;
            ev.hwndTrack = hWnd;
            ev.dwHoverTime = HOVER_DEFAULT;
            TrackMouseEvent(&ev);
        }
        return DefSubclassProc(hWnd, uMsg, wParam, lParam);
    }
    
    
        ...
        HWND hButton = CreateWindow(L"BUTTON", L"", WS_CHILD | WS_VISIBLE |
            BS_OWNERDRAW, 10, 10, 60, 30, hWnd,
            (HMENU)10001, hInst, NULL);
    
        SetWindowSubclass(hButton, Subclassproc, 101, 0);