使用方法:
procedure TfrmTest.FormCreate(Sender: TObject);
var
i, j: Integer;
FNode, FSubNode: TTreeNode;
begin
for i:=0 to 9 do
begin
FNode := zmCheckTreeView1.Items.AddChild(nil, '父节点' + IntToStr(i));
zmCheckTreeView1.CheckBoxState[FNode] := cbUnchecked;
for j:=0 to 9 do
begin
FSubNode := zmCheckTreeView1.Items.AddChild(FNode, '子节点' + IntToStr(i) + IntToStr(j));
zmCheckTreeView1.CheckBoxState[FSubNode] := cbUnchecked;
end;
end;
end;
destructor TzmCheckTreeView.Destroy;
begin
FStateImages.Free;
inherited;
end;
procedure TzmCheckTreeView.Loaded;
var
i: Integer;
begin
inherited Loaded;
for i := 0 to Items.Count - 1 do
SetChecked(Items[i], True);
end;
function TzmCheckTreeView.GetCheckBoxState(Node: TTreeNode): TCheckBoxState;
begin
if Node.StateIndex in [1..3] then
Result := TCheckBoxState(Node.StateIndex - 1)
else
Result := cbUnchecked;
end;
procedure TzmCheckTreeView.SetCheckBoxState(Node: TTreeNode;
const Value: TCheckBoxState);
begin
if (Node.StateIndex - 1 <> Ord(Value)) and (Value <> cbGrayed) then
begin
Node.StateIndex := Ord(Value) + 1;
SyncChildNode(Node);
SyncParentNode(Node);
end;
end;
function TzmCheckTreeView.GetChecked(Node: TTreeNode): Boolean;
begin
Result := GetCheckBoxState(Node) = cbChecked;
end;
procedure TzmCheckTreeView.SetChecked(Node: TTreeNode;
const Value: Boolean);
begin
if Value then
SetCheckBoxState(Node, cbChecked)
else
SetCheckBoxState(Node, cbUnchecked);
end;
function TzmCheckTreeView.ToggleChecked(Node: TTreeNode): Boolean;
begin
if Assigned(Node) then
begin
SetChecked(Node, not GetChecked(Node));
Result := True;
end
else
Result := False;
end;
function TzmCheckTreeView.ToggleCheckedByPos(x, y: Integer): Boolean;
var
Node: TTreeNode;
begin
Result := False;
if htOnStateIcon in GetHitTestInfoAt(x, y) then
begin
Node := GetNodeAt(x, y);
Result := ToggleChecked(Node);
end;
end;
procedure TzmCheckTreeView.KeyPress(var Key: Char);
begin
if (Key = ' ') and Assigned(Selected) then
ToggleChecked(Selected)
else
inherited;
end;
procedure TzmCheckTreeView.SyncChildNode(Node: TTreeNode);
var
i: Integer;
begin
if Node.StateIndex <> Ord(cbGrayed) + 1 then
for i := 0 to Node.Count - 1 do
begin
Node.Item[i].StateIndex := Node.StateIndex;
SyncChildNode(Node.Item[i]);
end;
end;
procedure TzmCheckTreeView.SyncParentNode(Node: TTreeNode);
var
i, SelCount, UnSelCount: Integer;
begin
if Node.Parent <> nil then
begin
SelCount := 0;
UnSelCount := 0;
for i := 0 to Node.Parent.Count - 1 do
begin
if GetCheckBoxState(Node.Parent.Item[i]) = cbChecked then
Inc(SelCount)
else if GetCheckBoxState(Node.Parent.Item[i]) = cbUnchecked then
Inc(UnSelCount);
end;
if SelCount = Node.Parent.Count then
begin
if GetCheckBoxState(Node.Parent) <> cbChecked then
begin
Node.Parent.StateIndex := Ord(cbChecked) + 1;
SyncParentNode(Node.Parent);
end;
end
else if UnSelCount = Node.Parent.Count then
begin
if GetCheckBoxState(Node.Parent) <> cbUnchecked then
begin
Node.Parent.StateIndex := Ord(cbUnchecked) + 1;
SyncParentNode(Node.Parent);
end;
end
else if GetCheckBoxState(Node.Parent) <> cbGrayed then
begin
Node.Parent.StateIndex := Ord(cbGrayed) + 1;
SyncParentNode(Node.Parent);
end;
end;
end;
procedure TzmCheckTreeView.WndProc(var message: TMessage);
begin
case message.Msg of
WM_LBUTTONDOWN, WM_LBUTTONDBLCLK:
begin
if ToggleCheckedByPos(TWMLButtonDown(message).XPos, TWMLButtonDown(message).YPos)
then
Exit;
end;
WM_LBUTTONUP, WM_RBUTTONUP:
begin
if htOnStateIcon in GetHitTestInfoAt(TWMLButtonDown(message).XPos,
TWMLButtonDown(message).YPos) then
Exit;
end;
end;
inherited WndProc(message);
end;
type
TForm1 = class(TForm)
fcTreeView1: TfcTreeView;
procedure SetChildrenCheck(TreeNode: TfcTreeNode; CheckStyle:Boolean);
procedure SetTreeViewCheck(TreeView:TfcTreeView);
procedure fcTreeView1Click(Sender: TObject);
procedure fcTreeView1Collapsing(TreeView: TfcCustomTreeView;
Node: TfcTreeNode; var AllowCollapse: Boolean);
procedure fcTreeView1Expanding(TreeView: TfcCustomTreeView;
Node: TfcTreeNode; var AllowExpansion: Boolean);
procedure FormShow(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
TreeStatus:Boolean;
implementation
{$R *.dfm}
procedure TForm1.SetChildrenCheck(TreeNode: TfcTreeNode; CheckStyle:Boolean);
var
CurrNode:TfcTreeNode;
begin
TreeNode.Checked:=CheckStyle;
if TreeNode.HasChildren then
begin
CurrNode:=TreeNode.GetFirstChild;
While CurrNode <> Nil do
begin
if CurrNode.HasChildren then
SetChildrenCheck(CurrNode,CheckStyle)
else
CurrNode.Checked:=CheckStyle;
CurrNode:=CurrNode.GetNextSibling;
end;
end;
end;
procedure TForm1.SetTreeViewCheck(TreeView: TfcTreeView);
var
CurrNode:TfcTreeNode;
i,CheckCount:integer;
begin
for i:=TreeView.Items.Count-1 downto 0 do
begin
if TreeView.Items[i].HasChildren then
begin
CheckCount:=0;
CurrNode:=TreeView.Items[i].GetFirstChild;
While CurrNode <> Nil do
begin
if CurrNode.Checked then CheckCount:=CheckCount+1;
CurrNode:=CurrNode.GetNextSibling;
end;
if CheckCount>0 then
TreeView.Items[i].Checked:=true
else
TreeView.Items[i].Checked:=false;
end;
end;
end;
procedure TForm1.fcTreeView1Click(Sender: TObject);
begin
if TreeStatus then begin TreeStatus:=false; exit; end;
fcTreeView1.Selected.Checked:=not fcTreeView1.Selected.Checked;
SetChildrenCheck(fcTreeView1.Selected,fcTreeView1.Selected.Checked);
SetTreeViewCheck(fcTreeView1);
end;
procedure TForm1.fcTreeView1Collapsing(TreeView: TfcCustomTreeView;
Node: TfcTreeNode; var AllowCollapse: Boolean);
begin
TreeStatus:=true;
end;
procedure TForm1.fcTreeView1Expanding(TreeView: TfcCustomTreeView;
Node: TfcTreeNode; var AllowExpansion: Boolean);
begin
TreeStatus:=true;
end;
procedure TForm1.FormShow(Sender: TObject);
begin
fcTreeView1.ReadOnly:=true;
end;