我正在使用复选框创建Treeview.我想出了如何切换到节点的复选框(过程ToggleTreeViewCheckBoxes).我添加了带有复选框位图的T
ImageList组件,并在OnClick treeview事件中更改StateIndex.它工作正常,但我想添加其他行为.
我创建了treeview结构作为示例:
>根1
>父1(复选框)
>儿童1(复选框)
>儿童2(复选框)
>父2(复选框)
>儿童1(复选框)
>儿童2(复选框)
>根2
>父1(复选框)
>儿童1(复选框)
>儿童2(复选框)
>父2(复选框)
>儿童1(复选框)
>儿童2(复选框)
unit TreeViewCheckBoxes; interface uses Winapi.Windows,Winapi.Messages,System.SysUtils,System.Variants,System.Classes,Vcl.Graphics,Vcl.Controls,Vcl.Forms,Vcl.Dialogs,System.ImageList,Vcl.ImgList,Vcl.ComCtrls; type TForm5 = class(TForm) ImageList1: timageList; TreeView1: TTreeView; procedure FormCreate(Sender: TObject); procedure TreeView1Click(Sender: TObject); private { Private declarations } procedure ToggleTreeViewCheckBoxes(Node:TTreeNode; cUnChecked,cChecked: Integer); public { Public declarations } end; var Form5: TForm5; const cStateUnCheck = 1; cStateChecked = 2; aRootList: Array[1..2] of String = ( 'Root 1','Root 2' ); implementation {$R *.dfm} { TForm5 } procedure TForm5.FormCreate(Sender: TObject); var RootNode: TTreeNode; ParentNode: TTreeNode; ChildNode: TTreeNode; i: Integer; begin for i := 1 to High(aRootList) do begin RootNode := TreeView1.Items.Add(nil,aRootList[i]); ParentNode := TreeView1.Items.AddChild(RootNode,'Parent 1'); ParentNode.StateIndex := 1; ChildNode := TreeView1.Items.AddChild(ParentNode,'Child 1'); ChildNode.StateIndex := 1; ChildNode := TreeView1.Items.AddChild(ParentNode,'Child 2'); ChildNode.StateIndex := 1; ParentNode := TreeView1.Items.AddChild(RootNode,'Parent 2'); ParentNode.StateIndex := 1; ChildNode := TreeView1.Items.AddChild(ParentNode,'Child 2'); ChildNode.StateIndex := 1; end; end; procedure TForm5.ToggleTreeViewCheckBoxes(Node: TTreeNode; cUnChecked,cChecked: Integer); begin if Assigned(Node) then begin if Node.StateIndex = cUnChecked then Node.StateIndex := cChecked else if Node.StateIndex = cChecked then Node.StateIndex := cUnChecked; end; end; procedure TForm5.TreeView1Click(Sender: TObject); var P: TPoint; begin GetCursorPos(P); P := TreeView1.ScreenToClient(P); if (htOnStateIcon in TreeView1.GetHitTestInfoAt(P.X,P.Y)) then ToggleTreeViewCheckBoxes(TreeView1.Selected,cStateUnCheck,cStateChecked); end; end.
问题:
1)我该怎么做呢:如果我点击任何Parent复选框节点,所有子节点都是未选中的?
2)您是否知道为所有子节点动态添加节点和设置StateIndex的更好方法?我的意思是没有每次都使用行ChildNode.StateIndex:= 1;
解决方法
1) How can I do something like that: If I click on any Parent checkBox node,all child nodes are unchecked?
您必须手动遍历所有子项,例如:
procedure TForm5.SetTreeViewCheckState(Node: TTreeNode; StateIndex: Integer; Recursive: Boolean); begin Node.StateIndex := StateIndex; if not Recursive then Exit; for I := 0 to Node.Count-1 do SetTreeViewCheckState(Node.Item[I],StateIndex,True); end; procedure TForm5.ToggleTreeViewCheckBoxes(Node: TTreeNode); var I: Integer; begin if Assigned(Node) then begin if Node.StateIndex = cStateUnCheck then SetTreeViewCheckState(Node,cStateChecked,False); else if Node.StateIndex = cStateChecked then SetTreeViewCheckState(Node,True); end; end;
2) Do you kNow any better way to dynamically add nodes and set StateIndex for all childs? I mean no every time use line ChildNode.StateIndex := 1;
procedure TForm5.FormCreate(Sender: TObject); var RootNode: TTreeNode; ParentNode: TTreeNode; i: Integer; begin for i := Low(aRootList) to High(aRootList) do begin RootNode := TreeView1.Items.Add(nil,aRootList[i]); ParentNode := AddChildNodeWithState(RootNode,'Parent 1'); AddChildNodeWithState(ParentNode,'Child 1'); AddChildNodeWithState(ParentNode,'Child 2'); ParentNode := AddChildNodeWithState(RootNode,'Parent 2'); AddChildNodeWithState(ParentNode,'Child 2'); end; end; function TForm5.AddChildNodeWithState(AParentNode: TTreeNode,const ACaption: String; AStateIndex: Integer = 1): TTreeNode; begin Result := TreeView1.Items.AddChild(AParentNode,ACaption); Result.StateIndex := AStateIndex; end;
或者,您可以创建一个class helper(也可以用于切换逻辑):
type TTreeNodeHelper = class helper for TTreeNode public function AddChildWithState(const ACaption: string; AStateIndex: Integer = 1): TTreeNode; procedure SetCheckState(StateIndex: Integer; Recursive: Boolean); procedure ToggleCheckState; end; function TTreeNodeHelper.AddChildWithState(const ACaption: string; AStateIndex: Integer = 1): TTreeNode; begin Result := Self.TreeView.Items.AddChild(Self,ACaption); Result.StateIndex := AStateIndex; end; procedure TTreeNodeHelper.SetCheckState(StateIndex: Integer; Recursive: Boolean); begin Self.StateIndex := StateIndex; if not Recursive then Exit; for I := 0 to Self.Count-1 do Self.Item[I].SetCheckState(StateIndex,True); end; procedure TTreeNodeHelper.ToggleCheckState; var I: Integer; begin if Self.StateIndex = cStateUnCheck then SetCheckState(cStateChecked,False); else if Self.StateIndex = cStateChecked then SetCheckState(cStateUnCheck,True); end; end;
procedure TForm5.FormCreate(Sender: TObject); var RootNode: TTreeNode; ParentNode: TTreeNode; i: Integer; begin for i := Low(aRootList) to High(aRootList) do begin RootNode := TreeView1.Items.Add(nil,aRootList[i]); ParentNode := RootNode.AddChildWithState('Parent 1'); ParentNode.AddChildWithState('Child 1'); ParentNode.AddChildWithState('Child 2'); ParentNode := RootNode.AddChildWithState('Parent 2'); ParentNode.AddChildWithState('Child 1'); ParentNode.AddChildWithState('Child 2'); end; end; procedure TForm5.TreeView1Click(Sender: TObject); var P: TPoint; begin GetCursorPos(P); P := TreeView1.ScreenToClient(P); if (htOnStateIcon in TreeView1.GetHitTestInfoAt(P.X,P.Y)) then TreeView1.GetNodeAt(P.X,P.Y).ToggleCheckState; end;
如果您使用的是不支持类助手的旧版Delphi,则可以从TTreeNode派生一个类,并将其与TreeView的OnCreateNodeClass
事件一起使用,例如:
type TMyTreeNode = class(TTreeNode) public function AddChildWithState(const ACaption: string; AStateIndex: Integer = 1): TTreeNode; procedure SetCheckState(StateIndex: Integer; Recursive: Boolean); procedure ToggleCheckState; end; function TMyTreeNode.AddChildWithState(const ACaption: string; AStateIndex: Integer = 1): TTreeNode; begin Result := Self.TreeView.Items.AddChild(Self,ACaption); Result.StateIndex := AStateIndex; end; procedure TMyTreeNode.SetCheckState(StateIndex: Integer; Recursive: Boolean); begin Self.StateIndex := StateIndex; if not Recursive then Exit; for I := 0 to Self.Count-1 do TMyTreeNode(Self.Item[I]).SetCheckState(StateIndex,True); end; procedure TMyTreeNode.ToggleCheckBoxes; var I: Integer; begin if Self.StateIndex = cStateUnCheck then SetCheckBoxes(cStateChecked,cStateUnChecked); else if Self.StateIndex = cStateChecked then SetCheckBoxes(cStateUnCheck,cStateUnChecked); end; end;
procedure TForm5.FormCreate(Sender: TObject); var RootNode: TTreeNode; ParentNode: TTreeNode; i: Integer; begin for i := Low(aRootList) to High(aRootList) do begin RootNode := TreeView1.Items.Add(nil,aRootList[i]); ParentNode := TMyTreeNode(RootNode).AddChildWithState('Parent 1'); TMyTreeNode(ParentNode).AddChildWithState('Child 1'); TMyTreeNode(ParentNode).AddChildWithState('Child 2'); ParentNode := TMyTreeNode(RootNode).AddChildWithState('Parent 2'); TMyTreeNode(ParentNode).AddChildWithState('Child 1'); TMyTreeNode(ParentNode).AddChildWithState('Child 2'); end; end; procedure TForm5.TreeView1Click(Sender: TObject); var P: TPoint; begin GetCursorPos(P); P := TreeView1.ScreenToClient(P); if (htOnStateIcon in TreeView1.GetHitTestInfoAt(P.X,P.Y)) then TMyTreeNode(TreeView1.GetNodeAt(P.X,P.Y)).ToggleCheckState; end; procedure TForm5.TreeView1CreateNodeClass(Sender: TCustomTreeView; var NodeClass: TTreeNodeClass) begin NodeClass := TMyTreeNode; end;