这个不错,只要指明id, name, parentid三个属性,调用RebuildTree,就可以了。
unit DBTrees;
interface
uses ComCtrls, DB, Classes, Sysutils;
type
TDBTreeView=class(TTreeView)
private
fTable:TDataSet;
fId,fParentId,fName:string;
function AddItem(var ParentIDList:TStringList):TTreeNode;
procedure GetInitParentID(var parentIdList:TStringList);
public
function GetId:integer;
procedure BuildTree;
procedure ClearTree;
function FindItem(Id:integer):TTreeNode;
function SelectItem(Id:integer):TTreeNode;
published
property FieldID:string Read fID Write fID;
property FieldParentID:string Read fParentId Write fParentId;
property FieldName:string Read fName Write fName;
property DataSource:TDataSet Read fTable Write fTable;
property ActiveId:integer Read GetId;
end;
procedure Register;
implementation
function TDBTreeView.FindItem(Id:integer):TTreeNode;
var
i:integer;
begin
Result:=nil;
For i:=0 to Items.Count-1 do
begin
if integer(Items.Data) = Id then
begin
Result:=Items;
Exit;
end;
end;
end;
function TDBTreeView.GetId:integer;
begin
If Selected=nil then Result:= -1
else Result:=integer(Selected.Data);
end;
procedure TDBTreeView.GetInitParentID(var parentIdList:TStringList);
var
childIdList:TStringList;
i:integer;
begin
childIDList := TStringList.Create;
try
parentIDList.Clear;
fTable.Filtered := false;
fTable.First;
While not fTable.Eof do
begin
parentIdList.add(fTable.FieldByName(fParentId).AsString);
if fTable.FieldByName(fParentId).AsString <> fTable.FieldByName(fId).AsString then
childIdList.add(fTable.FieldByName(fId).AsString);
fTable.next;
end;
for i := parentIdList.Count - 1 downto 0 do
begin
if childIdList.IndexOf(parentIdList) <> -1 then
parentIdList.Delete(i);
end;
finally
childIdList.Free;
end;
end;
function TDBTreeView.AddItem(var ParentIDList:TStringList):TTreeNode;
var
CurrentItem:TTreeNode;
Name:string;
CurId:integer;
begin
CurrentItem:=FindItem(fTable.FieldByName(fId).AsInteger);
//已经安装
If CurrentItem <> nil then
begin
Result := nil;
Exit;
end;
//父节点还未安装
if ParentIdList.Indexof(fTable.FieldByName(fParentID).AsString) = -1 then
begin
Result := nil;
exit;
end;
Name:=fTable.FieldByName(fName).AsString;
CurId :=fTable.FieldByName(fID).Asinteger;
//找到父节点,装在父节点下面
CurrentItem := FindItem(fTable.FieldByName(fParentID).Asinteger);
Result:=Items.AddChildObject(CurrentItem, Name, Pointer(CurID));
ParentIdList.Add(IntToStr(CurID));
end;
procedure TDBTreeView.BuildTree;
var
ChangeEvent:TTVChangedEvent;
initParentIdList:TStringList;
HasChanged:boolean;
begin
If (fTable=nil) or (not fTable.Active) then Exit;
ChangeEvent:=OnChange;
OnChange:=nil;
Items.BeginUpdate;
try
initParentIdList := TStringList.Create;
try
GetInitParentID(initParentIdList);
ClearTree;
HasChanged := true;
while HasChanged do
begin
HasChanged := false;
fTable.Filtered := false;
fTable.First;
While not fTable.Eof do
begin
if AddItem(initParentIdList) <> nil then
HasChanged := true;
fTable.Next;
end;
end;
finally
initParentIdList.Free;
end;
finally
Items.EndUpdate;
OnChange:=ChangeEvent;
end;
end;
procedure TDBTreeView.ClearTree;
begin
Items.BeginUpdate;
While Items.Count>0 do Items.Delete(Items[0]);
Items.EndUpdate;
end;
procedure Register;
begin
RegisterComponents('FromNetwork',[TDBTreeView]);
end;
function TDBTreeView.SelectItem(Id: integer): TTreeNode;
var
aNode:TTreeNode;
begin
result := FindItem(Id);
if result = nil then exit;
aNode := result.parent;
while aNode <> nil do
begin
aNode.Expand(false);
aNode := aNode.Parent;
end;
result.Selected := true;
end;
end.