unit MyTreeView;interfaceuses
    Classes, ComCtrls, Windows, CommCtrl, Controls;Type
    TMyTreeView = class(TTreeView)
    private
        { Private declarations }
        ClickNode: TTreeNode;               //  保存点中的节点
        NodeChecked: boolean;               //  保存点中的节点checked
        FIsModified: boolean;
    protected
        procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
            X, Y: Integer); override;
        procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
        {原型:
        procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
            X, Y: Integer); dynamic;
        procedure MouseMove(Shift: TShiftState; X, Y: Integer); dynamic;}    public
        { Public declarations }
        constructor Create(AOwner: TComponent); override;
        //设置树有CheckBox
        procedure SetCheckbox;
        function GetNodeChecked(aNode: TTreeNode): boolean;
        procedure SetNodeChecked(aNode: TTreeNode; isSetToChecked: boolean);
        procedure SetChildChecked(aNode: TTreeNode; yn: boolean);
    published
        property IsModified: boolean read FIsModified write FIsModified;
    end;implementationconstructor TMyTreeView.Create(AOwner: TComponent);
begin
    inherited;
    FIsModified := false;
end;procedure TMyTreeView.MouseDown(Button: TMouseButton; Shift: TShiftState;
    X, Y: Integer);
begin
{
      if (ClickNode!=NULL)
         if (GetNodeChecked(ClickNode)!=NodeChecked)
              // 把它的子孙都置成一样
               NodeChecked=!NodeChecked;  // 更新它
               SetChildChecked(ClickNode,NodeChecked);}
    if not (ClickNode = nil) then
        if not (GetNodeChecked(ClickNode) = NodeChecked) then
        begin
            NodeChecked := not NodeChecked;
            SetChildChecked(ClickNode, NodeChecked);
            FIsModified := true;
        end;
    inherited;
end;procedure TMyTreeView.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
{
      ClickNode=TreeView1->GetNodeAt(X,Y);
      if (ClickNode!=NULL)   // 保存原节点的Checked值
         NodeChecked=GetNodeChecked(ClickNode);
}
    ClickNode := self.GetNodeAt(X, Y);
    if not (ClickNode = nil) then
        NodeChecked := GetNodeChecked(ClickNode);
    inherited;
end;procedure TMyTreeView.SetCheckbox;
begin
    SetWindowLong(self.Handle, GWL_STYLE, GetWindowLong(self.Handle, GWL_STYLE) or TVS_CHECKBOXES);
end;function TMyTreeView.GetNodeChecked(aNode: TTreeNode): boolean;
var
    tvi: TV_ITEM;
begin
{
      TVITEM tvItem;
      tvItem.mask = TVIF_HANDLE | TVIF_STATE;
      tvItem.hItem = ANode->ItemId;
      tvItem.stateMask = TVIS_STATEIMAGEMASK;
      TreeView_GetItem(ANode->TreeView->Handle, &tvItem);
      return ((BOOL)(tvItem.state >> 12) -1);
}
    tvi.mask := TVIF_HANDLE or TVIF_STATE;
    tvi.hItem := aNode.ItemId;
    tvi.stateMask := TVIS_STATEIMAGEMASK;
    TreeView_GetItem(aNode.TreeView.Handle, tvi);
    Result := boolean((tvi.state shr 12) - 1);
end;procedure TMyTreeView.SetNodeChecked(aNode: TTreeNode; IsSetToChecked: boolean);
var
    tvi: TV_ITEM;
begin
{
      TVITEM tvItem;
      tvItem.mask = TVIF_HANDLE | TVIF_STATE;
      tvItem.hItem = ANode->ItemId;
      tvItem.stateMask = TVIS_STATEIMAGEMASK;
      tvItem.state = INDEXTOSTATEIMAGEMASK(IsSetToChecked?2:1);
      TreeView_SetItem(ANode->TreeView->Handle, &tvItem);
}
    tvi.mask := TVIF_HANDLE or TVIF_STATE;
    tvi.hItem := aNode.ItemId;
    tvi.stateMask := TVIS_STATEIMAGEMASK;
    if isSetToChecked then
        tvi.state := INDEXTOSTATEIMAGEMASK(2)
    else
        tvi.state := INDEXTOSTATEIMAGEMASK(1);
    TreeView_SetItem(aNode.TreeView.Handle, tvi);
end;procedure TMyTreeView.SetChildChecked(aNode: TTreeNode; yn: boolean);
var
    count, i: integer;
begin
{     // 把它的子孙都置成一样
      int count=ANode->Count;
      SetNodeChecked(ANode,yn);
      if (count!=0)
          for (int i=0;i<count;i++)    // 递归
             SetChildChecked(ANode->Item[i],yn);
}
    count := aNode.Count;
    SetNodeChecked(aNode, yn);
    if (count <> 0) then
        for i:=0 to count-1 do
            SetChildChecked(aNode.Item[i], yn);
end;end.