Обнаружить наведение курсора мыши на кнопку?

#c #winapi #ownerdrawn

#c #winapi #ownerdrawn

Вопрос:

У меня есть кнопка, нарисованная владельцем, которую я хотел бы выделить, когда мышь наводится на нее. Вот упрощенный код, который, похоже, не работает:

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

DrawButton это пользовательская функция, которая рисует кнопку. Вторым параметром этой функции является основной цвет кнопки. У функции нет проблем с отрисовкой кнопки. Проблема в обнаружении «состояния элемента».

Я также пробовал использовать if(pDraw->itemState amp; ODS_HOTLIGHT) . Это тоже не работает.

Очевидно, я что-то упускаю. В своем поиске я наткнулся на множество ответов. Однако ни один из них не находится на C .

Комментарии:

1. pDraw->itemState amp; ODS_HOTLIGHT это единственно правильная проверка, а не == . Постарайтесь убедиться, что вы действительно получили это сообщение о состоянии.

Ответ №1:

ODS_HOTLIGHT Кнопка может не использоваться. Посмотрите, какие состояния возможны в структуре DRAWITEMSTRUCT?.

Вы можете использовать подклассы, а затем использовать TrackMouseEvent для получения события 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(amp;ev);
    }
    else if (uMsg == WM_MOUSEHOVER)
    {
        RECT rc = {};
        GetClientRect(hWnd, amp;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, amp;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(amp;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);
 

Комментарии:

1. Спасибо Дрейку Ву за этот очень информативный код и описание. У меня только один вопрос / уточнение. В CreateWindow этом случае вы присваиваете идентификатор «10001». Однако при настройке подкласса вы используете число «101». Это опечатка? Или это два разных числа?

2. Это два разных значения. 10001 указывает hMenu , который можно использовать для получения уведомлений о кликах (WM_COMMAND=> wParam), а 101 указывает subclassid, который можно использовать для функции подкласса, например RemoveWindowSubclass

3. Спасибо. Я вижу разницу. В качестве альтернативного вопроса, можно ли использовать один и тот же номер в обоих случаях. Или это вызовет конфликт?

4. Нет. По крайней мере, образец, который я использовал, не противоречил друг другу. Эти два экземпляра представляют разные значения, и вы можете использовать одно и то же значение.

Ответ №2:

Как указано в описании ODS_HOTLIGHT значения:

ODS_HOTLIGHT: элемент отслеживается по горячим следам, то есть элемент будет выделен, когда мышь находится на элементе.

Итак, я полагаю, что для получения этого сообщения вам нужно сначала использовать TrackMouseEvent функцию.