| 風格 | 效果 |
TVS_HASLINES | 父子節點間繫連線 |
TVS_LINESATROOT | 根節點連線 |
TVS_HASBUTTONS | 節點前顯示展開/折疊按鈕(+/-) |
TVS_EDITLABELS | 標籤可編輯 |
TVS_SHOWSELALWAYS | 失去焦點仍高亮選中項 |
TVS_DISABLEDRAGDROP | 禁用拖放 |
TVS_NOTOOLTIPS | 禁用工具提示 |
TVS_CHECKBOXES | 節點前顯示複選框(擴展風格) |
TVS_FULLROWSELECT | 整行選中(擴展風格) |
TVS_INFOTIP | 支持信息提示(擴展風格) |
二、 節點核心操作
1. 插入節點
HTREEITEM InsertItem(LPCTSTR lpszItem, HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST);
hParent:父節點句柄,TVI_ROOT 表示根節點
hInsertAfter:插入位置,TVI_LAST 末尾,TVI_FIRST 首位,或具體兄弟句柄
- 返回值:新節點句柄
HTREEITEM
2. 帶圖標插入
HTREEITEM InsertItem(LPCTSTR lpszItem, int nImage, int nSelectedImage,
HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST);
nImage:未選中時圖標索引
nSelectedImage:選中時圖標索引
3. 構建樹形結構示例
HTREEITEM hRoot, hChild;
hRoot = m_tree.InsertItem(_T("Parent1"), TVI_ROOT);
hChild = m_tree.InsertItem(_T("Child1_1"), hRoot);
hChild = m_tree.InsertItem(_T("Child1_2"), hRoot, hChild); // 緊跟 Child1_1 後
hChild = m_tree.InsertItem(_T("Child1_3"), hRoot, hChild);
m_tree.InsertItem(_T("Parent2"), TVI_ROOT, hRoot);
m_tree.InsertItem(_T("Parent3"), TVI_ROOT, hRoot);
三、 圖標列表綁定
// 1. 創建圖標列表 (16x16, 4個圖標, 掩碼色黑色)
m_imageList.Create(IDB_TREE_BITMAP, 16, 4, RGB(0,0,0));
// 2. 綁定到樹控件
m_tree.SetImageList(&m_imageList, TVSIL_NORMAL);
// 3. 插入帶圖標節點
m_tree.InsertItem(_T("Parent1"), 0, 1); // 索引0未選中, 索引1選中
四、 節點狀態與文本控制
| 功能 | 獲取 | 設置 |
| 選中節點 | GetSelectedItem() | SelectItem(HTREEITEM) |
| 節點圖標 | GetItemImage(hItem, nImage, nSelImage) | SetItemImage(hItem, nImage, nSelImage) |
| 節點文本 | GetItemText(hItem) | SetItemText(hItem, lpszText) |
| 刪除節點 | - | DeleteItem(hItem) / DeleteAllItems() |
| 展開/折疊 | - | Expand(hItem, CODE) (TVE_EXPAND/TVE_COLLAPSE/TVE_TOGGLE) |
| 節點數據 | GetItemData(hItem) | SetItemData(hItem, DWORD_PTR) |
五、 樹遍歷算法
核心導航函數
GetRootItem():獲取根節點
GetChildItem(hParent):獲取第一個子節點
GetNextSiblingItem(hItem):獲取下一個兄弟節點
GetParentItem(hItem):獲取父節點
GetNextItem(hItem, CODE):通用導航(TVGN_NEXT, TVGN_PREVIOUS, TVGN_PARENT, TVGN_CHILD, TVGN_FIRSTVISIBLE 等)
遞歸遍歷模板
void TraverseTree(HTREEITEM hItem, int depth = 0) {
if (!hItem) return;
CString text = m_tree.GetItemText(hItem);
CString indent(' ', depth * 4);
TRACE(_T("%s%s\n"), indent, text);
// 遍歷子節點
HTREEITEM hChild = m_tree.GetChildItem(hItem);
while (hChild) {
TraverseTree(hChild, depth + 1);
hChild = m_tree.GetNextSiblingItem(hChild);
}
}
// 調用入口
HTREEITEM hRoot = m_tree.GetRootItem();
while (hRoot) {
TraverseTree(hRoot);
hRoot = m_tree.GetNextSiblingItem(hRoot);
}
非遞歸廣度優先遍歷(隊列)
void TraverseBFS() {
std::queue<HTREEITEM> q;
HTREEITEM hRoot = m_tree.GetRootItem();
while (hRoot) {
q.push(hRoot);
hRoot = m_tree.GetNextSiblingItem(hRoot);
}
while (!q.empty()) {
HTREEITEM h = q.front(); q.pop();
// 處理節點 h
HTREEITEM hChild = m_tree.GetChildItem(h);
while (hChild) {
q.push(hChild);
hChild = m_tree.GetNextSiblingItem(hChild);
}
}
}
六、 常用消息映射
| 通知代碼 | 觸發時機 | 結構 |
TVN_SELCHANGED | 選中項改變 | NMTREEVIEW |
TVN_ITEMEXPANDING | 節點即將展開/折疊 | NMTREEVIEW |
TVN_ITEMEXPANDED | 節點已展開/折疊 | NMTREEVIEW |
TVN_BEGINLABELEDIT | 開始編輯標籤 | NMTVDISPINFO |
TVN_ENDLABELEDIT | 結束編輯標籤 | NMTVDISPINFO |
TVN_GETDISPINFO | 動態文本回調 | NMTVDISPINFO |
TVN_BEGINDRAG | 開始拖動 | NMTREEVIEW |
NM_CLICK/NM_DBLCLK | 單擊/雙擊 | NMITEMACTIVATE |
TVN_KEYDOWN | 按鍵按下 | NMTVKEYDOWN |
七、 進階技巧
- 動態文本回調:插入時用
LPSTR_TEXTCALLBACK,處理 TVN_GETDISPINFO 填充 item.pszText
- 複選框支持:
SetExtendedStyle(TVS_EX_CHECKBOXES),用 GetCheck(hItem)/SetCheck(hItem, BOOL) 讀寫狀態
- 節點數據綁定:
SetItemData(hItem, (DWORD_PTR)pMyStruct) 關聯業務對象
- 自定義繪製:
TVS_OWNERDRAW + NM_CUSTOMDRAW 實現節點高亮、圖標動態、多字體
- 鍵盤導航增強:處理
TVN_KEYDOWN 實現字母快速定位、Enter 展開、空格勾選
- 保存/恢復展開狀態:遞歸記錄
GetItemState(hItem, TVIS_EXPANDED) 到配置文件
本文整理自 MFC 經典技術文檔,適用於 VC6~VS2022 所有版本。
- 上一篇文章: MFC 列表控件 CListCtrl 完整開發指南:四種視圖模式、圖標綁定、多列報表與動態回調
- 下一篇文章: MFC 組合框 CComboBox 完整開發指南:三種風格、列表/編輯雙重功能、查找選擇與消息映射
Copyright ©
程式碼之家 All Rights Reserved