简体   繁体   English

Win32 C++ ListView WM_CONTEXTMENU 问题

[英]Win32 C++ ListView WM_CONTEXTMENU Issue

I have a ListView with which I'd like to use a context menu that changes depending on selection.我有一个 ListView,我想用它来使用根据选择而变化的上下文菜单。 I'm making sure that I'm first able to display a menu when the right mouse button has been released (as per normal context menu behaviour).我确保在释放鼠标右键时我首先能够显示菜单(根据正常的上下文菜单行为)。

In my ListView WNDPROC I'm using WM_CONTEXTMENU to display the context menu.在我的 ListView WNDPROC我使用WM_CONTEXTMENU来显示上下文菜单。 The menu however is displayed at the location the cursor began the selection, not at the end.然而,菜单显示在光标开始选择的位置,而不是最后。

From the MS documentation :MS 文档

DefWindowProc generates the WM_CONTEXTMENU message when it processes the WM_RBUTTONUP or WM_NCRBUTTONUP message or when the user types SHIFT+F10. DefWindowProc 在处理 WM_RBUTTONUP 或 WM_NCRBUTTONUP 消息或用户键入 SHIFT+F10 时生成 WM_CONTEXTMENU 消息。 The WM_CONTEXTMENU message is also generated when the user presses and releases the VK_APPS key.当用户按下并释放 VK_APPS 键时,也会生成 WM_CONTEXTMENU 消息。

When I inspect the call stack, with a breakpoint in WM_CONTEXTMENU , I see that the message sent prior to WM_CONTEXTMENU was 0x0204 or WM_RBUTTONDOWN containing the coordinates of the cursor at this time.当我检查调用堆栈,在断点WM_CONTEXTMENU ,我看到该消息发送之前WM_CONTEXTMENU0x0204WM_RBUTTONDOWN包含光标的坐标在这个时候。 This probably explains the menu location issue, but why would this be happening?这可能解释了菜单位置问题,但为什么会发生这种情况?

When I hold the RMB down outside of the ListView and release it inside, the context menu still appears and I can see from the call stack that the last message was 0x0205 or WM_RBUTTONUP .当我在 ListView 之外按住 RMB 并在里面释放它时,上下文菜单仍然出现,我可以从调用堆栈中看到最后一条消息是0x0205WM_RBUTTONUP

Not sure whether I have something wrong in my code, or I'm not understanding something.不确定我的代码是否有问题,或者我不明白。 Any help on this issue would be greatly appreciated, thanks.对这个问题的任何帮助将不胜感激,谢谢。

Rather than relying on the WM_RBUTTON(DOWN|UP) messages to determine the mouse coordinates, the WM_CONTEXTMENU 's own lParam gives you the mouse's screen coordinates of the message that generated the WM_CONTEXTMENU . WM_RBUTTON(DOWN|UP)消息不是依靠WM_RBUTTON(DOWN|UP)消息来确定鼠标坐标, WM_CONTEXTMENU自己的lParam为您提供生成WM_CONTEXTMENU的消息的鼠标屏幕坐标。 If those coordinates are not what you are expecting, you can use GetMessagePos() instead, which will report the screen coordinates at the time WM_CONTEXTMENU was generated.如果这些坐标不是您所期望的,您可以改用GetMessagePos() ,它会报告生成WM_CONTEXTMENU时的屏幕坐标。 Either way, you can then convert the screen coordinates into ListView client coordinates using ScreenToClient() or MapWindowPoints() .无论哪种方式,你就可以将屏幕坐标转换为使用ListView的客户坐标ScreenToClient()MapWindowPoints()

Just be sure you also handle the case where the popup menu is being invoked by the user via keyboard input rather than mouse click.请确保您还处理了用户通过键盘输入而不是鼠标单击调用弹出菜单的情况。 In that case, the lParam of WM_CONTEXTMENU will carry the screen coordinates [x=-1,y=-1] , and you can query the ListView for the position of its selected item(s) using LVM_GETITEMPOSITION or LVM_GETITEMRECT as needed, then convert that position to screen coordinates using ClientToScreen() or MapWindowPoints() , and then display the popup menu at that screen location.在这种情况下, WM_CONTEXTMENUlParam将携带屏幕坐标[x=-1,y=-1] ,您可以根据需要使用LVM_GETITEMPOSITIONLVM_GETITEMRECT查询 ListView 其所选项目的位置,然后转换使用ClientToScreen()MapWindowPoints()将该位置转换为屏幕坐标,然后在该屏幕位置显示弹出菜单。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM