如何在列表控件中创建右键单击菜单?
How do I create a right-click menu in a list control?
( IDE : Visual C++ 6.0 )
我想使用列表控件来创建一个类似Windows任务管理器的程序。
添加通过api接收到的进程信息(item),并通过列表控件显示。
我想做的是右键单击特定项目,然后会出现一个对话框,就像一个真正的任务管理器。
搜索的结果,好像是用了OnContextMenu(CWnd*, CPoint)函数,但是没看懂是怎么回事
我希望你提供一个简单的例子。
谢谢:)
这是从我的一个项目中提取的工作样本。
请注意,此代码适用于 VS'15,可能 也适用于 VS'10。我没有 1998 版本...已经 20 年了。
我在代码中留下了一些注释。请仔细阅读这些内容。
CMenu m_Menu; //Class member
m_Menu.CreateMenu(); //Call this once only (I do it in PreSubclassWindow)
//class CMenuListCtrl : public CListCtrl
void CMenuListCtrl::OnContextMenu(CWnd *pWnd, CPoint ptMousePos)
{
//Some people might use a keyboard and not the mouse
if (ptMousePos.x == -1 && ptMousePos.y == -1)
{
auto nSelectedItem = GetSelectionMark(); //Get the selected item in the CListCtrl
if (nSelectedItem == -1)
return;
//Find the position
CRect itemRect;
GetItemRect(nSelectedItem, &itemRect, LVIR_BOUNDS);
ClientToScreen(&itemRect);
ptMousePos.x = itemRect.left + (itemRect.Width() / 10); //Some offset to display the menu user-friendly
ptMousePos.y = itemRect.top + itemRect.Height() / 2;
}
CPoint hitPoint = ptMousePos;
ScreenToClient(&hitPoint);
//Fix header pop-up bug
CHeaderCtrl *pHeader = GetHeaderCtrl();
HDHITTESTINFO hitTestHeader = {0};
hitTestHeader.pt = hitPoint;
//The header doesn't need a context-menu, the item does
if (pHeader->HitTest(&hitTestHeader) != -1)
return;
UINT uFlags = 0;
HitTest(hitPoint, &uFlags);
if (uFlags & LVHT_NOWHERE)
return;
//Get the previously created menu
CMenu *pPopUp = nullptr;
pPopUp = m_Menu.GetSubMenu(0);
if (pPopUp)
pPopUp->TrackPopupMenu(TPM_LEFTALIGN, ptMousePos.x, ptMousePos.y, this);
}
为了显示菜单,您必须先创建一个。
CMenu submenu;
submenu.CreatePopupMenu();
submenu.AppendMenuW(MF_STRING, IDC_COPY_POPUP, L"&Copy");
submenu.AppendMenuW(MF_SEPARATOR);
submenu.AppendMenuW(MF_STRING, IDC_DELETE_POPUP, L"&Delete");
m_Menu.AppendMenuW(MF_POPUP, reinterpret_cast<UINT_PTR>(submenu.m_hMenu), L"");
submenu.Detach();
( IDE : Visual C++ 6.0 )
我想使用列表控件来创建一个类似Windows任务管理器的程序。
添加通过api接收到的进程信息(item),并通过列表控件显示。
我想做的是右键单击特定项目,然后会出现一个对话框,就像一个真正的任务管理器。
搜索的结果,好像是用了OnContextMenu(CWnd*, CPoint)函数,但是没看懂是怎么回事
我希望你提供一个简单的例子。
谢谢:)
这是从我的一个项目中提取的工作样本。 请注意,此代码适用于 VS'15,可能 也适用于 VS'10。我没有 1998 版本...已经 20 年了。
我在代码中留下了一些注释。请仔细阅读这些内容。
CMenu m_Menu; //Class member
m_Menu.CreateMenu(); //Call this once only (I do it in PreSubclassWindow)
//class CMenuListCtrl : public CListCtrl
void CMenuListCtrl::OnContextMenu(CWnd *pWnd, CPoint ptMousePos)
{
//Some people might use a keyboard and not the mouse
if (ptMousePos.x == -1 && ptMousePos.y == -1)
{
auto nSelectedItem = GetSelectionMark(); //Get the selected item in the CListCtrl
if (nSelectedItem == -1)
return;
//Find the position
CRect itemRect;
GetItemRect(nSelectedItem, &itemRect, LVIR_BOUNDS);
ClientToScreen(&itemRect);
ptMousePos.x = itemRect.left + (itemRect.Width() / 10); //Some offset to display the menu user-friendly
ptMousePos.y = itemRect.top + itemRect.Height() / 2;
}
CPoint hitPoint = ptMousePos;
ScreenToClient(&hitPoint);
//Fix header pop-up bug
CHeaderCtrl *pHeader = GetHeaderCtrl();
HDHITTESTINFO hitTestHeader = {0};
hitTestHeader.pt = hitPoint;
//The header doesn't need a context-menu, the item does
if (pHeader->HitTest(&hitTestHeader) != -1)
return;
UINT uFlags = 0;
HitTest(hitPoint, &uFlags);
if (uFlags & LVHT_NOWHERE)
return;
//Get the previously created menu
CMenu *pPopUp = nullptr;
pPopUp = m_Menu.GetSubMenu(0);
if (pPopUp)
pPopUp->TrackPopupMenu(TPM_LEFTALIGN, ptMousePos.x, ptMousePos.y, this);
}
为了显示菜单,您必须先创建一个。
CMenu submenu;
submenu.CreatePopupMenu();
submenu.AppendMenuW(MF_STRING, IDC_COPY_POPUP, L"&Copy");
submenu.AppendMenuW(MF_SEPARATOR);
submenu.AppendMenuW(MF_STRING, IDC_DELETE_POPUP, L"&Delete");
m_Menu.AppendMenuW(MF_POPUP, reinterpret_cast<UINT_PTR>(submenu.m_hMenu), L"");
submenu.Detach();