2010-01-14 11 views
2

Je souhaite afficher un menu contextuel lorsqu'un utilisateur clique avec le bouton droit sur un élément dans une CListCtrl. Mon code est le suivant:HitTest ne fonctionne pas comme prévu

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) 
     } 
    } 
} 

Lorsque je cours réellement le code, peu importe où je clique; sur un élément, dans un espace vide dans CListCtrl, n'importe où ailleurs dans la boîte de dialogue (en supprimant la première instruction if); hitTestInfo.flags est mis à 48, ce qui, si je lis correctement this, signifie "Ci-dessous, et à droite de l'ensemble CListCtrl". Ce qui n'a pas vraiment de sens quand je vérifie d'abord si c'est dans la CListCtrl.

Est-ce que j'ai une supposition incorrecte quelque part? Est-ce que mon code est incorrect? Est-ce que je manque quelque chose?

En tant que peut-être liée, ou peut-être pas, BONUS QUESTION, à la fois LVHT_ONITEMSTATEICON et LVHT_ABOVE sont #define d comme 0x08 - pourquoi est-ce? Cela peut être la clé de mon malentendu.

Répondre

4

Je pense que HitTest() a besoin d'une position dans les coordonnées du client. Cela fait un moment que je ne l'ai pas fait pour la dernière fois, mais cela n'a pas de sens pour moi de passer des coordonnées d'écran dans une routine de test d'atteinte de fenêtre client. Ajouter m_itemList.ScreenToClient(&pos); avant hitTestInfo.pt = pos; et voir si cela aide.

En outre, notez que OnContextMenu() n'est peut-être pas l'appel que vous recherchez. Il est appelé en réponse à (par défaut) shift-f10 également. La documentation de WM_CONTEXTMENU est (en la lisant en diagonale, je ne me rappelle pas comment ça marche quand je l'ai fait la dernière fois) pas très claire sur ce que sera le contenu de 'pos' dans ce cas; vous devrez peut-être faire un GetCursorPos() explicite pour gérer ce cas. Ou affichez simplement votre contexte dans WM_RBUTTONDOWN.

+0

Merci beaucoup! Je vais aussi regarder dans la chose WM_RBUTTONDOWN - vous avez raison, cela provoque l'affichage incorrect du menu contextuel. – Smashery

+0

Si seulement je pouvais vous voter deux fois :-) – Smashery

+1

Le Pos passé dans OnContextMenu sera (-1, -1) je crois, dans le cas de Shift-F10 ou de la touche Menu dédiée. –

1

J'ai eu un problème similaire avec HitTest pour le contrôle de la liste. Il a l'effet obscur de retourner l'article 0 et LVHT_ONITEM drapeau même si un clic se produit sur l'en-tête. On s'attendrait à -1 pour l'index et LVHT_NOWHERE pour un drapeau. J'ai résolu cela en utilisant HitTest du contrôle d'en-tête. Voici comment:



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)) { 
... 
    } 
}