TTreeView 預設不支援複選框顯示,也缺乏「父節點選取時自動勾選所有子節點」的遞歸邏輯。本文示範如何透過 Windows API TVS_CHECKBOXES 樣式啟用內建複選框,並撰寫遞歸函式實現父子節點狀態同步,打造功能完整的樹狀選單介面。
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); // 遞歸同步所有子節點
}
}
}
GetNodeChecked 回傳的新狀態會與 NodeChecked(舊狀態)不同,觸發遞歸同步邏輯。SetChildChecked 會將點擊節點及其所有後代節點設為相同狀態,實現「勾選父節點 = 勾選整個子樹」的直覺操作。SetChildChecked 結束後向上遍歷檢查兄弟節點狀態。OnClick 或 OnChange 事件可即時更新 UI 或資料模型。BeginUpdate/EndUpdate 包裹遞歸操作以減少閃爍。這套方案僅使用 Windows 原生 API 與簡單遞歸,無需第三方元件,即可為 TreeView 注入專業級的複選框交互體驗。