HitTest 未按预期工作

发布于 2024-08-17 23:57:12 字数 1221 浏览 6 评论 0原文

我想在用户右键单击 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,如果我正在阅读 this 正确的意思是“在整个 CListCtrl 的下方和右侧”。当我第一次检查它是否在 CListCtrl 内时,这并没有什么意义。

那么我在某个地方有不正确的假设吗?我的代码不正确吗?我错过了什么吗?

作为一个可能相关或可能不相关的额外问题LVHT_ONITEMSTATEICONLVHT_ABOVE#define 为0x08 - 这是为什么?这可能是我误解的关键。

I am wanting to display a context menu when a user right-clicks on an item within a CListCtrl. My code is as follows:

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

When I actually run the code, regardless of where I click; on an item, in empty space within the CListCtrl, anywhere else on the dialog (by removing the first if statement); hitTestInfo.flags is set to 48, which, if I'm reading this correctly, means "Below, and to the right of the whole CListCtrl". Which doesn't really make sense when I'm first checking if it's within the CListCtrl.

So do I have an incorrect assumption somewhere? Is my code incorrect? Am I missing something?

As a possibly-related, or maybe not, BONUS QUESTION, both LVHT_ONITEMSTATEICON and LVHT_ABOVE are #defined as 0x08 - why is this? This may be key to my misunderstanding.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

惯饮孤独 2024-08-24 23:57:12

我认为 HitTest() 需要客户端坐标中的位置。自从我上次这样做以来已经有一段时间了,但是将屏幕坐标传递到客户端窗口命中测试例程对我来说没有意义。在 hitTestInfo.pt = pos; 之前添加 m_itemList.ScreenToClient(&pos); 并查看是否有帮助。

此外,请注意 OnContextMenu() 可能不是您正在寻找的调用。它也被调用以响应(默认情况下)shift-f10。 WM_CONTEXTMENU 的文档(对角阅读它时,我不记得上次执行此操作时它是如何工作的)不太清楚在这种情况下“pos”的内容是什么;您可能需要执行显式的 GetCursorPos() 来处理这种情况。或者只是在 WM_RBUTTONDOWN 中显示您的上下文。

I think HitTest() needs a position in client coordinates. It's been a while since I last did this, but it doesn't make sense to me to pass screen coordinates into a client window hit testing routine. Add m_itemList.ScreenToClient(&pos); before hitTestInfo.pt = pos; and see if that helps.

Furthermore, note that OnContextMenu() may not be the call you're looking for. It is called in response to (by default) shift-f10 as well. The documentation of WM_CONTEXTMENU is (on reading it diagonally, I don't remember how it works from when I last did this) not very clear on what the content of 'pos' will be in that case; you may need to do an explicit GetCursorPos() to handle that case. Or just show your context in WM_RBUTTONDOWN.

暮色兮凉城 2024-08-24 23:57:12

我对列表控制的 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)) {
...
    }
}

I had similar problem with HitTest for list control.
It has obscure effect of returning item 0 and LVHT_ONITEM flag
even if click occurs on the header. One would expect -1 for item
index and LVHT_NOWHERE for a flag.
I resolved this by using HitTest of header control. Here is how:



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)) {
...
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文