首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

CTreeCtrl 節點搜尋功能擴充:遞迴實作 FindItem 避免名稱重複

     編輯:關於VC++

在動態建立樹狀結構 (如目錄管理、組織架構) 時,新增節點前檢查名稱是否重複是基本需求。MFC CTreeCtrl 未提供內建搜尋方法,本文示範衍生 CTreeCtrlEx 加入 FindItem 遞迴搜尋函式,並搭配 TVN_ENDLABELEDIT 實作「編輯標籤時自動查重」的完整範例。

執行畫面:編輯節點名稱時自動檢查重複。

核心函式:FindItem (CTreeCtrlEx.cpp)

HTREEITEM CTreeCtrlEx::FindItem(HTREEITEM hItem, CString strText) { if (!hItem) return NULL; while (hItem) { // 1. 比對目前節點 if (GetItemText(hItem) == strText) return hItem; // 2. 有子節點 → 遞迴搜尋子樹 if (ItemHasChildren(hItem)) { HTREEITEM hChild = GetChildItem(hItem); HTREEITEM hFound = FindItem(hChild, strText); if (hFound) return hFound; // 子樹找不到 → 移至下一個兄弟節點 (需取得父節點再取下一個兄弟) hItem = GetNextSiblingItem(GetParentItem(hChild)); } else { // 3. 無子節點 → 直接移至下一個兄弟 hItem = GetNextSiblingItem(hItem); if (!hItem) return NULL; // 已達樹尾 } } return NULL; }

演算法說明: 深度優先搜尋 (DFS)。依序檢查「目前節點 → 子樹 → 兄弟節點」。利用 GetParentItem + GetNextSiblingItem 實現回溯至父層繼續搜尋兄弟。

完整範例:對話框專案 MyTreeCtrl

1. 資源與變數對應

控件ID成員變數/函式
Tree ControlIDC_MYTREECTreeCtrl m_ctrlTree (後改為 CTreeCtrlEx)
ButtonIDC_NEWITEMOnNewitem()
樹狀項目暫存-HTREEITEM m_hInsertItem

2. 新增節點按鈕處理

void CMyTreeCtrlDlg::OnNewitem() { HTREEITEM hSel = m_ctrlTree.GetSelectedItem(); if (!hSel) hSel = TVI_ROOT; // 無選取則掛在根下 m_hInsertItem = m_ctrlTree.InsertItem(_T("新項目"), hSel); m_ctrlTree.SelectItem(m_hInsertItem); m_ctrlTree.Expand(hSel, TVE_EXPAND); // 進入編輯模式 m_ctrlTree.EditLabel(m_hInsertItem); }

3. 編輯標籤開始 — 限制長度

void CMyTreeCtrlDlg::OnBeginlabeleditMytree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR; m_ctrlTree.GetEditControl()->LimitText(16); // 最長 16 字元 *pResult = 0; }

4. 編輯標籤結束 — 核心查重邏輯

void CMyTreeCtrlDlg::OnEndlabeleditMytree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR; CString strName; m_ctrlTree.GetEditControl()->GetWindowText(strName); if (strName.IsEmpty()) { AfxMessageBox(_T("節點名稱不可為空!")); m_ctrlTree.EditLabel(m_hInsertItem); // 重新編輯 *pResult = 0; return; } HTREEITEM hRoot = m_ctrlTree.GetRootItem(); HTREEITEM hFound = m_ctrlTree.FindItem(hRoot, strName); if (!hFound) { // 未重複 → 確認對話框 CString msg; msg.Format(_T("確定新增節點「%s」嗎?"), strName); if (MessageBox(msg, _T("提示"), MB_OKCANCEL) == IDOK) *pResult = TRUE; // 接受新名稱 else m_ctrlTree.DeleteItem(m_hInsertItem); // 取消 → 刪除剛建立的項目 } else { AfxMessageBox(_T("該節點名稱已存在,請重新輸入!")); m_ctrlTree.EditLabel(m_hInsertItem); // 重新編輯 *pResult = 0; // 拒絕新名稱 } }

關鍵點總結

  • FindItem 為遞迴 DFS,時間複雜度 O(N),N 為節點總數,滿足一般規模樹狀結構需求。
  • TVN_BEGINLABELEDIT 限制輸入長度;TVN_ENDLABELEDIT 執行查重與使用者確認。
  • 若取消新增,務必 DeleteItem(m_hInsertItem) 清理暫存節點。
  • 專案設定:AppWizard 建立 Dialog-based,語言設為 Chinese (PRC) 以支援中文介面。

測試環境:Win98 + VC6.0 通過。現代環境 (VS2019+) 同樣適用,只需注意字元集設定 (Unicode/MBCS)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved