问题描述
我有一个ListView,我想使用它根据上下文选择而变化的上下文菜单。我确保在释放鼠标右键后(根据正常的上下文菜单行为)我首先能够显示菜单。
在我的ListView WNDPROC
中,我使用WM_CONTEXTMENU
显示上下文菜单。但是,菜单显示在光标开始选择的位置,而不是结束。
DefWindowProc在处理WM_RBUTTONUP或WM_NCRBUTTONUP消息时或在用户键入SHIFT + F10时,会生成WM_CONTEXTMENU消息。当用户按下并释放VK_APPS键时,也会生成WM_CONTEXTMENU消息。
当我检查调用堆栈时,在WM_CONTEXTMENU
中有一个断点,我发现在WM_CONTEXTMENU
之前发送的消息是0x0204
或WM_RBUTTONDOWN
,其中包含此时光标。这可能可以解释菜单位置问题,但是为什么会发生这种情况?
当我将RMB放到ListView外面并放到里面时,上下文菜单仍然出现,并且从调用堆栈中可以看到最后一条消息是0x0205
或WM_RBUTTONUP
。
解决方法
WM_RBUTTON(DOWN|UP)
自己的WM_CONTEXTMENU
而不是依靠lParam
消息来确定鼠标坐标,而是为您提供生成{{1}的消息的鼠标屏幕坐标}。如果这些坐标不是您期望的坐标,则可以使用WM_CONTEXTMENU
代替,它将在生成GetMessagePos()
时报告屏幕坐标。无论哪种方式,您都可以使用WM_CONTEXTMENU
或ScreenToClient()
将屏幕坐标转换为ListView客户端坐标。
只要确保您还处理用户通过键盘输入而不是单击鼠标来调用弹出菜单的情况。在这种情况下,MapWindowPoints()
的{{1}}将带有屏幕坐标lParam
,您可以使用WM_CONTEXTMENU
或在ListView中查询其选定项目的位置。 [x=-1,y=-1]
根据需要,然后使用LVM_GETITEMPOSITION
或LVM_GETITEMRECT
将该位置转换为屏幕坐标,然后在该屏幕位置显示弹出菜单。