Как я могу открыть и закрыть всплывающее меню, когда я нажимаю на окно в Win32 API? - PullRequest
1 голос
/ 01 апреля 2020

Я сделал небольшое окно с API Win32 и хочу открыть всплывающее меню, когда я нажимаю на окно. Когда я нажимаю на него снова, я хочу закрыть меню, если оно все еще открыто.

Я открываю меню на WM_LBUTTONUP , потому что я хочу перетащить окно на WM_LBUTTONDOWN .

Я знаю, когда меню появляется или исчезает по WM_ENTERMENUL OOP и WM_EXITMENUL OOP.

Я знаю, как закрыть меню программно, но, к сожалению, я не знаю, как решить, открыто ли меню или закрыто на WM_LBUTTONUP . Проблема в том, что меню автоматически закрывается WM_LBUTTONDOWN , и поэтому я не могу сохранить текущее состояние меню.

Было бы здорово, если у кого-то есть подсказка, как решить Эта проблема.

Дополнительная информация:

  • все окно представляет собой клиентскую область без полей с растровым изображением

    hWnd = CreateWindowExW(WS_EX_TOPMOST, L"MyWindow", 0, WS_POPUP, wndPosX, wndPosY, m_WndWidth, m_WndHeight, 0, 0, m_hInst, 0);
    
  • растровое изображение загружается в WM_CREATE в WindowProcedure окна и окрашивается в WM_PAINT

    m_hBitmap = (HBITMAP)LoadImageA(NULL, "MyBitmap.bmp", IMAGE_BITMAP, m_WndWidth, m_WndHeight, LR_LOADFROMFILE);
    
  • окно по умолчанию не перетаскивается, потому что у меня нет не клиентской области, поэтому я вручную перемещаю окно на WM_MOUSEMOVE в соответствии с текущей позицией курсора

  • Вкл. WM_LBUTTONUP Я создаю всплывающее меню в верхней части окна

    HMENU hPopupMenu = CreatePopupMenu();
    InsertMenuW(hPopupMenu, 0, MF_BYPOSITION | MF_STRING, ID_ITEM_A, L"ItemA");
    SetForegroundWindow(hWnd);
    RECT wndRect;
    GetWindowRect(hWnd, &wndRect);
    TrackPopupMenu(hPopupMenu, TPM_BOTTOMALIGN | TPM_LEFTALIGN, wndRect.left, wndRect.top, 0, hWnd, NULL);
    

1 Ответ

0 голосов
/ 02 апреля 2020

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

в глобальной области действия

static HHOOK hMouseHook = 0;
static HWND hMainWindow = 0;
static int nSkipClick = 0;

LRESULT CALLBACK MouseProc(_In_ int    nCode, _In_ WPARAM wParam, _In_ LPARAM lParam)
{
    if (nCode < 0)
        return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
    if (wParam == WM_LBUTTONDOWN) {
        MOUSEHOOKSTRUCT* p = (MOUSEHOOKSTRUCT*)lParam;
        if (WindowFromPoint(p->pt) == hMainWindow) {
            POINT pt = p->pt;
            ScreenToClient(hMainWindow, &pt);
            RECT rct;
            GetClientRect(hMainWindow, &rct);
            if (PtInRect(&rct, pt))nSkipClick = 1;
        }
    }
    return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
}

в WndPro c

case WM_LBUTTONUP: 
    if (nSkipClick == 0) { // menu not shown before
        hMouseHook = SetWindowsHookEx(WH_MOUSE, &MouseProc, NULL, GetCurrentThreadId());
        hMainWindow = hWnd;
        HMENU hPopupMenu = CreatePopupMenu();
        InsertMenuW(hPopupMenu, 0, MF_BYPOSITION | MF_STRING, ID_ITEM_A, L"ItemA");
        SetForegroundWindow(hWnd);
        RECT wndRect;
        GetWindowRect(hWnd, &wndRect);
        TrackPopupMenu(hPopupMenu, TPM_BOTTOMALIGN | TPM_LEFTALIGN, wndRect.left, wndRect.top, 0, hWnd, NULL);
        UnhookWindowsHookEx(hMouseHook);
        hMouseHook = 0;
    }
    else {
        nSkipClick = 0;
    }
break;

Я надеюсь, что это то, что вы хотите сделать.

...