c++ - How can I open and close a popup menu when I click on a window in win32 api?
问题描述
I made a little window with the win32 api and want to open a popup menu when I click on the window. When I click on it again I want to close the menu if it's still open.
I open the menu on WM_LBUTTONUP, because I want to drag the window on WM_LBUTTONDOWN.
I know when the menu appears or disappears by WM_ENTERMENULOOP and WM_EXITMENULOOP.
I know how to close the menu programmatically, but unfortunately I don't know how to decide whether the menu is open or closed on WM_LBUTTONUP. The problem is that the menu gets automatically closed on WM_LBUTTONDOWN and that's why I can't save the current state of the menu.
It would be great if someone has a hint how to solve this problem.
Additional information:
the whole window is a borderless client-area with a bitmap painted on it
hWnd = CreateWindowExW(WS_EX_TOPMOST, L"MyWindow", 0, WS_POPUP, wndPosX, wndPosY, m_WndWidth, m_WndHeight, 0, 0, m_hInst, 0);
the bitmap gets loaded on WM_CREATE in the WindowProcedure of the window and is painted on WM_PAINT
m_hBitmap = (HBITMAP)LoadImageA(NULL, "MyBitmap.bmp", IMAGE_BITMAP, m_WndWidth, m_WndHeight, LR_LOADFROMFILE);
the window isn't draggable by default, because I don't have a non-client area, that's why I move the window manually on WM_MOUSEMOVE according to the current cursor position
On WM_LBUTTONUP I create the popup menu on top of the window
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);
解决方案
这是使用 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);
}
在 WndProc 中
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;
我希望这是你想做的。
推荐阅读
- swiftui - SwiftUI 将计算变量传递给下一个视图
- node.js - MongoDB长时间错过保存数据
- java - 正则表达式删除 CSV 中双引号内的换行符
- flutter - 如何让用户上传任意数量的图片。因此可以根据需要上传 1 到 5 张图片
- sql - 如何在postgres中找到具有相同列的列的最大值和值?
- html - 使用 Brython 向 HTML 表格添加超链接
- jquery - 更改列标题文本后对 jQuery DataTable 进行排序
- apache-kafka - 用例:构造一条在 kafka 中某个时间后消失的消息
- android - 我真的不明白何时在数据绑定中使用 ViewDataBinding.invalidateAll()
- python - Python urlopener 不检索表和列表