Visual c++ 如何保证我为用户在CTreeControl中右键单击的项目获取“HTREEITEM”

Visual c++ 如何保证我为用户在CTreeControl中右键单击的项目获取“HTREEITEM”,visual-c++,mfc,Visual C++,Mfc,我有一个窗口,它有一个CTreeCtrl。用户可以右键单击任何元素并显示关联菜单。从那里他们可以选择删除条目。大概是这样的: 以下是上下文菜单项处理程序的一个片段: void CAssignHistoryDlg::OnDeleteFromAssignmentHistory() { CString strINI = theApp.GetAssignHistoryPath(); HTREEITEM hItem = m_treeHistory.GetSel

我有一个窗口,它有一个
CTreeCtrl
。用户可以右键单击任何元素并显示关联菜单。从那里他们可以选择删除条目。大概是这样的:

以下是上下文菜单项处理程序的一个片段:

void CAssignHistoryDlg::OnDeleteFromAssignmentHistory()
{
    CString         strINI = theApp.GetAssignHistoryPath();
    HTREEITEM       hItem = m_treeHistory.GetSelectedItem();
    CString         strName, strDeletedName, strEntry;

    if (m_treeHistory.GetParentItem(hItem) != nullptr)
    {
        // The user has picked one of the history dates.
        // So the parent should be the actual name.
        hItem = m_treeHistory.GetParentItem(hItem);

        // Now OK to proceed
    }

    strName = ExtractName(hItem);

    GetParent()->EnableWindow(FALSE);
    strEntry.Format(IDS_TPL_SURE_DELETE_FROM_ASSIGN_HIST, strName);
    if (AfxMessageBox(strEntry, MB_YESNO | MB_ICONQUESTION) == IDNO)
    {
图中显示了我的问题。如果我首先点击测试,使被选中和亮蓝色,,然后右击,它在弹出消息中显示测试。这很好。但是

如果名字最初选中的,并且我继续并直接右键单击测试,即使它看起来变成蓝色(好像选中了),
m_treeHistory.GetSelectedItem()
将返回原始的名字。我想我描述得不太好

简而言之,我想保证为用户右键单击的项目获得
HTREEITEM
。我所拥有的不是100%的傻瓜

如果有帮助,以下是我显示关联菜单的方式:

void CAssignHistoryDlg::OnNMRclickTreeHistory(NMHDR *pNMHDR, LRESULT *pResult)
{
    CMenu           mnuContext, *pMnuEdit = nullptr;
    CPoint          ptLocal;
    LPNMTREEVIEW    pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);

    GetCursorPos(&ptLocal);

    mnuContext.LoadMenu( IDR_MENU_SM_ASSIGN_HIST_POPUP );
    pMnuEdit = mnuContext.GetSubMenu( 0 );
    if (pMnuEdit != nullptr)
    {
        pMnuEdit->TrackPopupMenu( TPM_LEFTALIGN|TPM_LEFTBUTTON,
                    ptLocal.x, ptLocal.y, this, nullptr );
    }

    *pResult = 0;
}
void CAssignHistoryDlg::OnNMRclickTreeHistory(NMHDR*pNMHDR,LRESULT*pResult)
{
CMenu mnuContext,*pMnuEdit=nullptr;
C点局部;
LPNMTREEVIEW pNMTreeView=重新解释铸件(pNMHDR);
GetCursorPos(&ptLocal);
mnuContext.LoadMenu(IDR\u菜单\u SM\u分配\u历史\u弹出窗口);
pMnuEdit=mnuContext.GetSubMenu(0);
如果(pMnuEdit!=nullptr)
{
pMnuEdit->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON,
ptLocal.x,ptLocal.y,this,nullptr);
}
*预设值=0;
}
因此,总而言之,此时用户必须在树中的某个项目上单击鼠标左键才能选择它。然后,他们可以右键单击,它将提供删除此人。但是,如果他们继续,只需右键单击任何人,它将不会提供删除该人的功能。

您可以使用
CTreeCtrl
类的成员在任何给定点获取实际的树项。具体执行方式和位置取决于代码设计,但是,如果您有指向
CTreeCtrl
pwTree
)的指针,则可以执行以下操作:

CPoint ptLocal;
GetCursorPos(&ptLocal);
pWTree->ScreenToClient(&ptLocal);//在某些处理程序中可能不需要?
HTREEITEM hItem=pWTree->HitTest(ptLocal);//记得检查空返回!
然后,您可以直接使用返回的hItem,或者在进行任何进一步处理之前,使用它显式地设置树的选择(该项)。

MS文档:没有“单击”处理程序,它有
CWnd::onrbuttonblclk
CWnd::OnRButtonDown
CWnd::OnRButtonUp
。你在处理哪一个

缺陷的原因可能是您不让树控件处理右键事件(选择新项)


我建议改用
CWnd::OnContextMenu

我已经找到了这篇文章,正在阅读。非常感谢。我让它工作了。但是,我必须将
OnNMRclickTreeHistory
处理程序中的
CPoint
缓存到变量中。然后,按照你的指示使用它。这是因为菜单项本身向下向右偏移,因此
HitTest
响应是错误的项。通过在右键单击处理程序中缓存该点并随后使用该点,它将始终导出正确的项!再次感谢。:)你好公认的答案是解决方案。我使用NM_RCLICK。看@AndrewTruckle——即使这解决了你的问题,也很难解决;充其量也就是胡扯。您正在删除在调用
OnDeleteFromAssignmentHistory
时光标指向的项目,该项目可能是调用菜单时选择的正常项目,也可能不是。我会试图找出预期选择与实际选择不匹配的原因,我认为我的建议会真正解决这个问题。@AndrewTruckle-我做了一些测试,右键单击本身似乎不会改变CTreeCtrl中的选择;您可以找到光标下的项目并调用
CTreeCtrl::SelectItem()
。我真的相信这是处理选择的正确方法。例如:你真的读过知识库的文章吗?它使用我正在使用的处理程序,并获取该处理程序中的鼠标位置。它使用该信息模拟内容菜单处理程序并发布消息。然后使用
HitTest
。这不是正常情况。这是一个
CTreeCtrl
,它是不同的。我很感谢你的回答,但指导是明确的。我们能不能就到此为止?谢谢