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

在 C++Builder TreeView 中實現複選框與節點遞歸選取

     編輯:VC 教學

前言

TTreeView 預設不支援複選框顯示,也缺乏「父節點選取時自動勾選所有子節點」的遞歸邏輯。本文示範如何透過 Windows API TVS_CHECKBOXES 樣式啟用內建複選框,並撰寫遞歸函式實現父子節點狀態同步,打造功能完整的樹狀選單介面。

啟用 TreeView 複選框

void __fastcall TForm1::FormCreate(TObject *Sender)
{
    // 取得現有樣式並加入 TVS_CHECKBOXES
    SetWindowLong(TreeView1->Handle, GWL_STYLE,
        GetWindowLong(TreeView1->Handle, GWL_STYLE) | TVS_CHECKBOXES);
}

此 API 呼叫會讓 TreeView 以系統原生方式繪製複選框,無需自繪,效能最佳。

核心輔助函式

取得節點勾選狀態

bool GetNodeChecked(TTreeNode *ANode)
{
    TVITEM tvItem;
    tvItem.mask = TVIF_HANDLE | TVIF_STATE;
    tvItem.hItem = ANode->ItemId;
    tvItem.stateMask = TVIS_STATEIMAGEMASK;
    TreeView_GetItem(ANode->TreeView->Handle, &tvItem);
    // 狀態影像索引:1=未勾選, 2=勾選;右移 12 位後減 1 得到布林值
    return ((BOOL)(tvItem.state >> 12) - 1);
}

設定節點勾選狀態

void SetNodeChecked(TTreeNode *ANode, bool IsSetToChecked)
{
    TVITEM tvItem;
    tvItem.mask = TVIF_HANDLE | TVIF_STATE;
    tvItem.hItem = ANode->ItemId;
    tvItem.stateMask = TVIS_STATEIMAGEMASK;
    // INDEXTOSTATEIMAGEMASK(2) = 勾選, INDEXTOSTATEIMAGEMASK(1) = 未勾選
    tvItem.state = INDEXTOSTATEIMAGEMASK(IsSetToChecked ? 2 : 1);
    TreeView_SetItem(ANode->TreeView->Handle, &tvItem);
}

遞歸設定子節點狀態

void SetChildChecked(TTreeNode *ANode, bool yn)
{
    int count = ANode->Count;
    SetNodeChecked(ANode, yn);           // 先設定自身
    if (count != 0)
        for (int i = 0; i < count; i++)  // 遞歸處理所有子節點
            SetChildChecked(ANode->Item[i], yn);
}

滑鼠事件實現點擊切換與遞歸同步

TTreeNode *ClickNode;  // 暫存點擊的節點
bool NodeChecked;      // 暫存點擊前的勾選狀態

void __fastcall TForm1::TreeView1MouseMove(TObject *Sender,
    TShiftState Shift, int X, int Y)
{
    ClickNode = TreeView1->GetNodeAt(X, Y);
    if (ClickNode != NULL)
        NodeChecked = GetNodeChecked(ClickNode);  // 記錄點擊前狀態
}

void __fastcall TForm1::TreeView1MouseDown(TObject *Sender,
    TMouseButton Button, TShiftState Shift, int X, int Y)
{
    if (ClickNode != NULL)
    {
        // 若目前狀態與點擊前不同,表示使用者剛切換了複選框
        if (GetNodeChecked(ClickNode) != NodeChecked)
        {
            NodeChecked = !NodeChecked;           // 更新快取狀態
            SetChildChecked(ClickNode, NodeChecked); // 遞歸同步所有子節點
        }
    }
}

運作邏輯說明

  1. MouseMove:滑鼠移動時持續偵測游標下的節點,並記錄該節點當前的勾選狀態。
  2. MouseDown:當使用者點擊複選框時,系統會先翻轉狀態,此時 GetNodeChecked 回傳的新狀態會與 NodeChecked(舊狀態)不同,觸發遞歸同步邏輯。
  3. 遞歸同步:SetChildChecked 會將點擊節點及其所有後代節點設為相同狀態,實現「勾選父節點 = 勾選整個子樹」的直覺操作。

進階應用建議

  • 若需「子節點全勾選時自動勾選父節點」,可在 SetChildChecked 結束後向上遍歷檢查兄弟節點狀態。
  • 搭配 OnClick 或 OnChange 事件可即時更新 UI 或資料模型。
  • 大量節點時建議使用 BeginUpdate/EndUpdate 包裹遞歸操作以減少閃爍。

這套方案僅使用 Windows 原生 API 與簡單遞歸,無需第三方元件,即可為 TreeView 注入專業級的複選框交互體驗。

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