// 单击节点判断, 点的是何位置procedure TMsgShowFilterDlg.tv1Click(Sender: TObject);var Node: TTreeNode; P: TPoint;begin Node := tv1.Selected; if Node = nil then Exit; if not GetCursorPos(P) then Exit; // 得到光标的位置 P := tv1.ScreenToClient(P); // ComCtrls 单元 TTreeView的各个位置都枚举出来了 // THitTest = (htAbove, htBelow, htNowhere, htOnItem, htOnButton, htOnIcon, // htOnIndent, htOnLabel, htOnRight, htOnStateIcon, htToLeft, htToRight); if (htOnicon in tv1.GetHitTestInfoAt(P.X, P.Y)) then begin FTreeViewImp.ModifyTreeNodeState(Node); end;end;// 以下是我的辅助管理类unit Unit1;interfaceuses StdCtrls, ComCtrls;type // 出自 StdCtrls.TCheckBox 的状态// TCheckBoxState = (cbUnchecked, cbChecked, cbGrayed); // TTreeView **Click 触发的事件 TMsgSelChanged = procedure(ATreeNode: TTreeNode) of object; TTreeViewImp = class(TObject) private FTreeView: TTreeView; FOnMsgSelChanged: TMsgSelChanged; procedure DoOnMsgSelChanged(ATreeNode: TTreeNode); // 遍历 ATreeNode 的 所有子节点 (不含 ATreeNode) procedure RecursionChildNode(ATreeNode: TTreeNode; const AChkState: TCheckBoxState); // 遍历 ATreeNode 的 父节点 (不含 ATreeNode) procedure RecursionParentNode(ATreeNode: TTreeNode; const AChkState: TCheckBoxState); // 遍历 ATreeNode 的 兄弟节点 (含 ATreeNode) : 返回父节点的状态 function RecursionSiblingNode(ATreeNode: TTreeNode): TCheckBoxState; // 遍历一棵树 (只传根节点进去) procedure RefreshTreeView(ATreeNode: TTreeNode); // 单个节点的处理 procedure DealOneTreeNode(ATreeNode: TTreeNode; const AChkState: TCheckBoxState); public constructor Create(ATreeView: TTreeView; const ANetType: Integer); // 修改一个节点的状态, IsChanged: 表示是否已处理过本节点的状态了 procedure ModifyTreeNodeState(ATreeNode: TTreeNode; const IsChanged: Boolean = False); property OnMsgSelChanged: TMsgSelChanged read FOnMsgSelChanged write FOnMsgSelChanged; end;implementation// 遍历 ATreeNode 的 所有子节点 (不含 ATreeNode)constructor TTreeViewImp.Create(ATreeView: TTreeView; const ANetType: Integer);begin FTreeView := ATreeView; // .................... // 你的初始化生成树 //.....................end;procedure TTreeViewImp.DealOneTreeNode(ATreeNode: TTreeNode; const AChkState: TCheckBoxState);begin if ATreeNode.ImageIndex <> Ord(AChkState) then begin ATreeNode.ImageIndex := Ord(AChkState); ATreeNode.SelectedIndex := ATreeNode.ImageIndex; // 修改数组记录 DoOnMsgSelChanged(ATreeNode); end;end;procedure TTreeViewImp.DoOnMsgSelChanged(ATreeNode: TTreeNode);begin if Assigned(FOnMsgSelChanged) then FOnMsgSelChanged(ATreeNode);end;procedure TTreeViewImp.ModifyTreeNodeState(ATreeNode: TTreeNode; const IsChanged: Boolean = False);var Node: TTreeNode; ChkState, ModifiedState: TCheckBoxState;begin if ATreeNode = nil then Exit; Node := ATreeNode; ChkState := TCheckBoxState(Node.ImageIndex); if not IsChanged then begin // 本来未选中的, 则选中 if ChkState = cbUnchecked then ModifiedState := cbChecked else ModifiedState := cbUnchecked; end else ModifiedState := ChkState; // 修改自己状态 (选中) DealOneTreeNode(Node, ModifiedState); // 修改子节点 (递归全选) RecursionChildNode(Node, ModifiedState); // 查看所有兄弟节点状态, 于决定父节点状态// ModifiedState := RecursionSiblingNode(Node); while Node.Parent <> nil do begin ModifiedState := RecursionSiblingNode(Node); DealOneTreeNode(Node.Parent, ModifiedState); Node := Node.Parent; end; // 修改父节点 (递归) RecursionParentNode(Node, ModifiedState);end;procedure TTreeViewImp.RecursionChildNode(ATreeNode: TTreeNode; const AChkState: TCheckBoxState);var Node, SiblingNode: TTreeNode;begin if ATreeNode = nil then Exit; Node := ATreeNode.getFirstChild; while Node <> nil do begin SiblingNode := Node.getNextSibling; // ===================== // 对 Node 进行条件处理 DealOneTreeNode(Node, AChkState); // ===================== if Node.HasChildren then RecursionChildNode(Node, AChkState); // 有子节点, 再递归下去 // 转接下一个兄弟节点 Node := SiblingNode; end;end;// 遍历 ATreeNode 的 父节点 (不含 ATreeNode)procedure TTreeViewImp.RecursionParentNode(ATreeNode: TTreeNode; const AChkState: TCheckBoxState);var Node: TTreeNode;begin if ATreeNode = nil then Exit; Node := ATreeNode.Parent; while Node <> nil do begin // ===================== // 对 Node 进行条件处理 DealOneTreeNode(Node, AChkState); // ===================== // 下一个兄弟节点 Node := Node.Parent; end; end;// 遍历 ATreeNode 的 兄弟节点 (含 ATreeNode)function TTreeViewImp.RecursionSiblingNode(ATreeNode: TTreeNode): TCheckBoxState;var Node: TTreeNode; HasChecked: Boolean;begin HasChecked := False; Result := cbUnchecked; // 默认 if ATreeNode = nil then Exit; Node := ATreeNode.Parent; if Node = nil then Node := FTreeView.Items[0]; // 说明是第一层节点 if Node = nil then Exit; Result := cbChecked; // 默认选中, 再检查 Node := Node.getFirstChild; while Node <> nil do begin // ===================== // 对 Node 进行条件处理 if Node.ImageIndex = Ord(cbGrayed) then // 有灰的 begin Result := cbGrayed; Exit; end else if Node.ImageIndex = Ord(cbUnchecked) then // 有未选中的 begin if (Result <> cbGrayed) then // and Result <> cbUnChecked Result := cbUnchecked; end else if Node.ImageIndex = Ord(cbChecked) then // 有选中的 begin HasChecked := True; end; // ===================== // 下一个兄弟节点 Node := Node.getNextSibling; end; if HasChecked and (Result = cbUnchecked) then Result := cbGrayed;end;// 遍历一棵树procedure TTreeViewImp.RefreshTreeView(ATreeNode: TTreeNode);var Node, SiblingNode: TTreeNode;begin if ATreeNode = nil then Exit; Node := ATreeNode; while Node <> nil do begin SiblingNode := Node.getNextSibling; // 到叶子结点则修改状态 if not Node.HasChildren then // Node.Level = 2 then begin ModifyTreeNodeState(Node, True);// Exit; end else// if Node.HasChildren then begin Node := Node.getFirstChild; RefreshTreeView(Node); end; // 转接下一个兄弟节点 Node := SiblingNode; end;end;end.