在 WTL 專案中,常需根據樹狀檢視(CTreeViewCtrl)的節點結構,動態建立右鍵選單的子選單項目。本文提供完整實作步驟與代碼片段。
// 取得右鍵選單的第 0 個子選單(主選單),再取得其第 MY_MOVE_FRIENT_MENU_POS 個子選單(目標子選單)
CMenuHandle menu = pMenu->GetSubMenu(0).GetSubMenu(MY_MOVE_FRIENT_MENU_POS);
// 從後往前刪除,避免索引偏移
for (int i = menu.GetMenuItemCount(); i > 0; --i)
{
menu.RemoveMenu(i, MF_BYPOSITION);
}
注意:動態新增的選單項目不會自動銷毀,每次彈出前必須先清空,否則項目會重複疊加。
// 取得根節點
HTREEITEM hRoot = m_wndLocalList.GetRootItem();
// 取得第一個子節點(第一個群組)
HTREEITEM hFirst = m_wndLocalList.GetChildItem(hRoot);
CString strFirst;
if (hFirst)
m_wndLocalList.GetItemText(hFirst, strFirst);
int nMenuID = 0; // 動態分配的命令 ID 起始偏移
while (hFirst != NULL)
{
// 略過「目前所屬群組」(不需移動到自己所在群組)
if (strFirst.Compare(strItemSelParent) != 0)
{
// 插入選單項目:位置 -1(尾部)、按位置、字串類型、動態 ID、顯示文字
menu.InsertMenu(-1, MF_BYPOSITION | MF_STRING,
(UINT)(ID_MENU_ADD_FRIEND_TO_GROUP + nMenuID),
strFirst);
++nMenuID;
}
// 移至下一個同層節點
hFirst = m_wndLocalList.GetNextItem(hFirst, TVGN_NEXT);
if (hFirst)
m_wndLocalList.GetItemText(hFirst, strFirst);
}
在訊息映射巨集區塊加入:
BEGIN_MSG_MAP(YourDialogClass)
// ... 其他映射 ...
COMMAND_RANGE_HANDLER(ID_MENU_ADD_FRIEND_TO_GROUP,
ID_MENU_ADD_FRIEND_TO_GROUP + 100,
OnMenuAddToFriendGroupRange)
END_MSG_MAP()
COMMAND_RANGE_HANDLER 將連續 100 個 ID 導向同一處理函式。ID_MENU_ADD_FRIEND_TO_GROUP 定義為 const int,需確保不與 resource.h 衝突。
LRESULT OnMenuAddToFriendGroupRange(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
// 1. 取得使用者點選的葉子節點
HTREEITEM hItemSel = m_wndLocalList.GetSelectedItem();
if (!hItemSel) return 0;
CString strSelectedText;
m_wndLocalList.GetItemText(hItemSel, strSelectedText);
// 2. 從樹狀列表移除該節點
m_wndLocalList.DeleteItem(hItemSel);
// 3. 根據 wID 反推目標群組節點 hGroupItem
// (需遍歷群組節點比對 ID_MENU_ADD_FRIEND_TO_GROUP + index == wID)
HTREEITEM hGroupItem = FindGroupItemByMenuID(wID);
// 4. 插入到目標群組下(按字母排序 TVI_SORT)
HTREEITEM hNewItem = m_wndLocalList.InsertItem(strSelectedText, hGroupItem, TVI_SORT);
// 5. 通知伺服器更新群組關係
add_to_group();
return 0;
}
| API | 用途 |
|---|---|
CMenuHandle::GetSubMenu(int) | 取得子選單控制碼 |
CMenuHandle::GetMenuItemCount() | 取得選單項目數 |
CMenuHandle::RemoveMenu(UINT, UINT) | 移除項目 (MF_BYPOSITION / MF_BYCOMMAND) |
CMenuHandle::InsertMenu(UINT, UINT, UINT, LPCTSTR) | 插入項目 |
CTreeViewCtrl::GetRootItem() | 取得根節點 |
CTreeViewCtrl::GetChildItem(HTREEITEM) | 取得第一個子節點 |
CTreeViewCtrl::GetNextItem(HTREEITEM, UINT) | 取得下一個節點 (TVGN_NEXT 同層) |
CTreeViewCtrl::GetItemText(HTREEITEM, CString&) | 取得節點文字 |
CTreeViewCtrl::InsertItem(LPCTSTR, HTREEITEM, HTREEITEM) | 插入節點 |
COMMAND_RANGE_HANDLER(idFirst, idLast, handler) | WTL 巨集:命令 ID 範圍映射 |
+100 若群組超過 100 個會溢位,動態計算上限或擴大範圍。TVS_TRACKSELECT:右鍵未自動選中節點,需手動 SelectItem。CString、LPCTSTR 皆為寬字元,插入選單無需轉換。