HitTest работает не так, как ожидалось - PullRequest
2 голосов
/ 14 января 2010

Я хочу отобразить контекстное меню, когда пользователь щелкает правой кнопкой мыши элемент в CListCtrl. Мой код выглядит следующим образом:

void DatastoreDialog::OnContextMenu(CWnd *pWnd, CPoint pos)
{
    // Find the rectangle around the list control
    CRect rectMainArea;
    m_itemList.GetWindowRect(&rectMainArea);
    // Find out if the user right-clicked the list control
    if( rectMainArea.PtInRect(pos) )
    {
        LVHITTESTINFO hitTestInfo;
        hitTestInfo.pt = pos;
        hitTestInfo.flags = LVHT_ONITEM;
        m_itemList.HitTest(&hitTestInfo);
        if (hitTestInfo.flags & LVHT_NOWHERE)
        {
             // No item was clicked
        }
        else 
        {
            MyContextHandler(hitTestInfo)
        }
    }
}

Когда я запускаю код, независимо от того, где я нажимаю; для элемента, в пустом пространстве внутри CListCtrl, в любом другом месте диалогового окна (удаляя первый оператор if); hitTestInfo.flags имеет значение 48, что, если я правильно читаю , это , означает «Ниже и справа от всего CListCtrl». Что на самом деле не имеет смысла, когда я впервые проверяю, находится ли он в CListCtrl.

Так у меня где-то неверное предположение? Мой код неверен? Я что-то пропустил?

Как возможно связанный или, возможно, нет, БОНУСНЫЙ ВОПРОС , оба LVHT_ONITEMSTATEICON и LVHT_ABOVE имеют #define d как 0x08 - почему это? Это может быть ключом к моему недоразумению.

Ответы [ 2 ]

4 голосов
/ 14 января 2010

Я думаю, что HitTest () нуждается в позиции в клиентских координатах. Прошло много времени с тех пор, как я это делал в последний раз, но для меня не имеет смысла передавать экранные координаты в процедуру тестирования попаданий в окне клиента. Добавьте m_itemList.ScreenToClient(&pos); перед hitTestInfo.pt = pos; и посмотрите, поможет ли это.

Кроме того, обратите внимание, что OnContextMenu () может быть не тем звонком, который вы ищете. Он также вызывается в ответ на (по умолчанию) shift-f10. Документация к WM_CONTEXTMENU (при чтении по диагонали, я не помню, как она работает с того момента, когда я в последний раз делал это), не очень ясно, каким будет содержание pos в этом случае; вам может потребоваться сделать явное GetCursorPos() для обработки этого случая. Или просто покажите свой контекст в WM_RBUTTONDOWN.

1 голос
/ 06 апреля 2011

У меня была похожая проблема с HitTest для управления списком. Имеет неясный эффект возврата элемента 0 и флага LVHT_ONITEM даже если щелчок происходит в заголовке. Можно ожидать -1 для элемента индекс и LVHT_NOWHERE для флага. Я решил это с помощью HitTest контроля заголовка. Вот как:



UINT uFlags = 0;
CHeaderCtrl* pHdr = m_list.GetHeaderCtrl();
if (!pHdr) return;  // sanity
HDHITTESTINFO hitTestInfo = {0};
hitTestInfo.pt = ptClient;
int iItem = pHdr->HitTest(&hitTestInfo);
if ((iItem != -1) && ((HHT_ONHEADER | HHT_ONDIVIDER) & hitTestInfo.flags)) {
    // this is header control menu
    CWnd::OnContextMenu(pWnd, point);
}
else if (HHT_BELOW & hitTestInfo.flags) {
    CXTMenu Menu;
    // this is list view control menu
    if (Menu.LoadMenu(IDR_LIST_CONTEXT)) {
...
    }
}
...