Win32 C++ ListView WM_CONTEXTMENU Проблема

У меня есть ListView, с которым я хотел бы использовать контекстное меню, которое меняется в зависимости от выбора. Я удостоверяюсь, что я могу сначала отобразить меню, когда правая кнопка мыши была отпущена (согласно обычному поведению контекстного меню).

В моем ListView WNDPROC я использую WM_CONTEXTMENU для отображения контекстного меню. Однако меню отображается в том месте, где курсор начал выделение, а не в конце.

Из документации MS:

DefWindowProc генерирует сообщение WM_CONTEXTMENU, когда он обрабатывает сообщение WM_RBUTTONUP или WM_NCRBUTTONUP или когда пользователь набирает SHIFT+F10. Сообщение WM_CONTEXTMENU также генерируется, когда пользователь нажимает и отпускает клавишу VK_APPS.

Когда я проверяю стек вызовов с точкой останова в WM_CONTEXTMENU, я вижу, что сообщение, отправленное до WM_CONTEXTMENU, было 0x0204 или WM_RBUTTONDOWN и содержало координаты курсора в это время. Это, вероятно, объясняет проблему с расположением меню, но почему это происходит?

Когда я удерживаю ПКМ за пределами ListView и отпускаю его внутри, контекстное меню все еще появляется, и я вижу из стека вызовов, что последним сообщением было 0x0205 или WM_RBUTTONUP.

Не уверен, что у меня что-то не так в моем коде, или я чего-то не понимаю. Любая помощь по этому вопросу будет принята с благодарностью, спасибо.


person Synthetic Ascension    schedule 23.10.2020    source источник
comment
Ах да, извините, сейчас исправлю.   -  person Synthetic Ascension    schedule 23.10.2020
comment
При обработке WM_CONTEXTMENU дает ли GetMessagePos() правильные координаты, которые вы ищете?   -  person Remy Lebeau    schedule 23.10.2020
comment
Оно делает. Интересно, есть ли WM_RBUTTONUP после WM_CONTEXTMENU, что приводит к тому, что GetMessagePos() получает от него координаты мыши?   -  person Synthetic Ascension    schedule 23.10.2020
comment
А как насчет координат, сообщенных самим WM_CONTEXTMENU?   -  person Remy Lebeau    schedule 23.10.2020
comment
Координаты из LPARAM содержатся в сообщении WM_RBUTTONDOWN.   -  person Synthetic Ascension    schedule 23.10.2020


Ответы (1)


Вместо того, чтобы полагаться на сообщения WM_RBUTTON(DOWN|UP) для определения координат мыши, собственное lParam WM_CONTEXTMENU дает вам экранные координаты мыши сообщения, которое сгенерировало WM_CONTEXTMENU. Если эти координаты не соответствуют вашим ожиданиям, вы можете вместо этого использовать GetMessagePos(), который сообщит координаты экрана на момент создания WM_CONTEXTMENU. В любом случае вы можете затем преобразовать координаты экрана в координаты клиента ListView, используя ScreenToClient() или MapWindowPoints().

Просто убедитесь, что вы также обрабатываете случай, когда всплывающее меню вызывается пользователем с помощью ввода с клавиатуры, а не щелчка мыши. В этом случае lParam из WM_CONTEXTMENU будет содержать координаты экрана [x=-1,y=-1], и вы можете запросить у ListView положение выбранного элемента(ов), используя LVM_GETITEMPOSITION или LVM_GETITEMRECT по мере необходимости, а затем преобразовать это положение в координаты экрана, используя ClientToScreen() или MapWindowPoints(), а затем отобразите всплывающее меню в этом месте экрана.

person Remy Lebeau    schedule 23.10.2020
comment
Спасибо за это. Интересно, что ListViews в MMC, похоже, имеют ту же проблему, что и я, тогда как если вы выбираете элементы в проводнике Windows и отпускаете ПКМ вне элемента управления, он не будет отображать контекстное меню, а просто выберет элементы. - person Synthetic Ascension; 23.10.2020