fctreeview带checkbox的状态下如何实现像杀毒软件选择目录那样的效果。比如:
一、选中一个父结点的时候,它的所有子结点都被选中。当取消其选中状态,它的子结点的选中状态也被取消;
二、选中一个有父结点的结点,其所有的父结点也都被选中。
三、只要存在有子结点被选中,则对应的父结点为选中状态。

解决方案 »

  1.   

    你在OnChange事件里面就可以做到了
      

  2.   

    一定要写递规unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, fcTreeView, StdCtrls;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;end.
      

  3.   

    给你一个控件,自己编译一下吧:
    unit zmCheckTreeView;interfaceuses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      ComCtrls, Commctrl, StdCtrls;
      
    type  TzmCheckTreeView = class(TTreeView)
      private
        { Private declarations }
        FStateImages: TImageList;
        function GetCheckBoxState(Node: TTreeNode): TCheckBoxState;
        procedure SetCheckBoxState(Node: TTreeNode;
          const Value: TCheckBoxState);
        function GetChecked(Node: TTreeNode): Boolean;
        procedure SetChecked(Node: TTreeNode; const Value: Boolean);
      protected
        { Protected declarations }
        procedure WndProc(var message: TMessage); override;
        procedure KeyPress(var Key: Char); override;
        procedure Loaded; override;
        function ToggleCheckedByPos(x, y: Integer): Boolean;
        function ToggleChecked(Node: TTreeNode): Boolean;
        procedure SyncChildNode(Node: TTreeNode);
        procedure SyncParentNode(Node: TTreeNode);
      public
        { Public declarations }
        constructor Create(AOwner: TComponent); override;
        destructor Destroy; override;    property CheckBoxState[Node: TTreeNode]: TCheckBoxState read GetCheckBoxState
          write SetCheckBoxState;
        property Checked[Node: TTreeNode]: Boolean read GetChecked write SetChecked;
      end;procedure Register;implementation{$R zmCheckTreeView.res}{ TzmCheckTreeView }procedure Register;
    begin
      RegisterComponents('zmSoft', [TzmCheckTreeView]);
    end;constructor TzmCheckTreeView.Create(AOwner: TComponent);
    begin
      inherited;
      FStateImages := TImageList.CreateSize(16, 16);
      FStateImages.Handle := ImageList_LoadBitmap(hInstance, 'ZMTREESTATUS',
        16, 0, clFuchsia);
      StateImages := FStateImages;
    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;end.
      

  4.   

    其中zmCheckTreeView.res是一个资源文件,建立一个宽64高16的Bitmap,也就是4中状态16×16图标,第一个16×16图标是空的(表示不使用CheckBox模式),第二个16×16图标是未选中,第三个16×16图标是表示全部子节点选中,第四个16×16图标是表示部分子节点选中。然后把这个Bitmap资源名称修改为ZMTREESTATUS就可以安装了!
      

  5.   

    使用方法:
    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;