Использовать диапазон команд для динамического меню
Это может быть очень простой вопрос, но поскольку новичок не понимает причину, в основном я хочу всплывающее меню на древовидном элементе управления, например, при щелчке правой кнопкой мыши на древовидном элементе управления появляется одно меню, а на основе этого меню - другие функции. я использовал следующий код,
в.h файле,
#define NEW_RELAY_MENU_START WM_USER + 1
#define NEW_RELAY_MENU_END WM_USER + 256
в.cpp файле
BEGIN_MESSAGE_MAP(CCtrlModDefDlgTree, CTreeCtrl)
ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelChangedTreeCtrl)
ON_NOTIFY_REFLECT(NM_RCLICK, &CCtrlModDefDlgTree::OnNMRClick)
ON_COMMAND_RANGE(NEW_RELAY_MENU_START,NEW_RELAY_MENU_END,CCtrlModDefDlgTree::OnNewMenu)
END_MESSAGE_MAP()
CCtrlModDefDlgTree::CCtrlModDefDlgTree()
{
NumberOfRelays.RemoveAll();
NumberOfRelays.Add(L"MENU1");
NumberOfRelays.Add(L"MENU2");
NumberOfRelays.Add(L"MENU3");
NumberOfRelays.Add(L"MENU4");
NumberOfRelays.Add(L"MENU5);
NumberOfRelays.Add(L"MENU6");
}
void CCtrlModDefDlgTree::OnNMRClick(NMHDR *pNMHDR, LRESULT *pResult)
{
// TODO: Add your control notification handler code here
/* Get the cursor position for this message */
DWORD dwPos = GetMessagePos();
/* Convert the co-ords into a CPoint structure */
CPoint pt( GET_X_LPARAM( dwPos ), GET_Y_LPARAM ( dwPos ) );
CPoint spt;
spt = pt;
/* convert to screen co-ords for the hittesting to work */
ScreenToClient( &spt );
UINT test;
HTREEITEM hti = HitTest( spt, &test );
if ( hti != NULL )
{
/* Is the click atcually *on* the item? */
if ( test & TVHT_ONITEM )
{
/* Do the normal context menu stuff */
ShowPopupMenu( pt );
}
}
*pResult = 0;
}
void CCtrlModDefDlgTree::ShowPopupMenu( CPoint& point )
{
if (point.x == -1 && point.y == -1)
{
//keystroke invocation
CRect rect;
GetClientRect(rect);
ClientToScreen(rect);
point = rect.TopLeft();
point.Offset(5, 5);
}
//create a menu object for main menu
CMenu *menu = new CMenu();
menu->CreatePopupMenu();
//another menu object for submenu
CMenu *subMenu = new CMenu();
subMenu->CreatePopupMenu();
for(int __index = 0;__index<NumberOfRelays.GetCount();__index++)
{
subMenu->AppendMenu(MF_STRING, NEW_RELAY_MENU_START+__index, NumberOfRelays.ElementAt(__index));
}
//append submenu to menu
menu->AppendMenu(MF_POPUP|MF_STRING, (UINT)subMenu->m_hMenu, _T("New Menu") );
ASSERT(menu != NULL);
CWnd* pWndPopupOwner = this;
while (pWndPopupOwner->GetStyle() & WS_CHILD)
pWndPopupOwner = pWndPopupOwner->GetParent();
menu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,
pWndPopupOwner);
}
void CCtrlModDefDlgTree::OnNewMenu(UINT nID)
{
}
Но моя функция OnNewMenu() не вызывается при щелчке по меню. Даже все меню по умолчанию включены. Что я делаю не так?
1 ответ
Вы добавили диапазон команд к карте сообщений для древовидного элемента управления, но не используете древовидный элемент управления в качестве окна владельца для меню.
CWnd* pWndPopupOwner = this;
while (pWndPopupOwner->GetStyle() & WS_CHILD)
pWndPopupOwner = pWndPopupOwner->GetParent();
Это найдет окно верхнего уровня и будет использовать его в качестве владельца всплывающего окна, что означает WM_COMMAND
сообщения из всплывающего окна будут отправляться в окно верхнего уровня, а не в дерево. Вам нужно добавить диапазон команд к карте сообщений этого окна.
Кроме того, вы можете использовать TPM_RETURNCMD
флаг с TrackPopupMenu
который вернет идентификатор выбранной команды, а затем вызовет ваш OnNewMenu()
функционировать себя:
int iID = menu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
point.x, point.y, pWndPopupOwner);
if (iID) OnNewMenu(iID);