核心提示:但是非叶节点的Filter操作依然是无可避免的。而Filter又是影响整个生成的最重要因素,因此当带子节点的节点很多时,速度还是要被拖下去的。 后来我看到了一种觉得不错的思路,就是用调整节点的方法来...
但是非叶节点的Filter操作依然是无可避免的。而Filter又是影响整个生成的最重要因素,因此当带子节点的节点很多时,速度还是要被拖下去的。
后来我看到了一种觉得不错的思路,就是用调整节点的方法来形成树。先一次过把所有数据当根节点加进TreeList中,然后再根据它们之间的ID和PID关系来进行节点调整,这样就可以避免数据集的Filter操作了。而影响算法的主要因素,变成了查找关系时的IndexOf操作,和节点移动的方法MoveTo,不过相对于Filter来说,这个肯定要更高效了。
虽然思路不是我先想出来的,不过具体的调整方法是自己想的。
600) this.width = 600;">
procedure GenerateTreeListEx(AKeyField, AParentField: string; ADataSet: TDataSet; ATree: TTreeView);
function CreateNewNode(ADataSet: TDataSet; ATree: TTreeView): TTreeNode;var
pCodeValue: PString;
begin
// 这里写你的TreeNode读写逻辑,添加到根节点下就行
// 现以用Data属性来保存代码值为例,假设代码名字段叫"CodeName",代码值字段叫"CodeValue"
result := ATree.Add(nil, ADataSet['CodeName']);
New(pCodeValue);
pCodeValue^ := ADataSet['CodeValue'] ;
result.Data := pCodeValue;
end; var
APidList, AItems, AChildItems: TStringList;
i, j, k, iIndex: integer;
sPID: string;
begin
APidList := TStringList.Create; APidList.Sorted := true; //把结果进行排序,这样可以通过搜索算法(Find的二分查找)提高索引效率,重要
ATree.Items.BeginUpdate;
try
// 读取数据集
for i := 1 to ADataSet.RecordCount do
begin
if VarIsNull(ADataSet[AParentField]) then
sPID := 'NULL'
else
sPID := ADataSet[AParentField];
// 查找该PID是不是已经在PidList里存在
if not APidList.Find(sPID, iIndex) then
iIndex := APidList.AddObject(ADataSet[AParentField], TStringList.Create);
with TStringList(APidList.Objects[iIndex]) do
AddObject(ADataSet[AKeyField], CreateTreeNode(ADataSet, ATree)); ADataSet.Next;
end;
// 调整节点
for i := 0 to APidList.Count - 1 do
begin
AItems := TStringList(APidList.Objects[i]);
for j := 0 to AItems.Count - 1 do
begin
if APidList.Find(AItems[j], iIndex) then
begin
AChildItems := TStringList(APidList.Objects[iIndex]);
for k := 0 to AChildItems.Count - 1 do
TTreeNode(AChildItems.Objects[k]).MoveTo(TTreeNode(AItems.Objects[j]), naAddChild); // 由于MoveTo会导致节点展开,因此把它重新折叠起来 TTreeNode(AItems.Objects[j]).Collapse(false);
end;
end;
end;
finally
// 释放资源等
for i := 0 to APidList.Count - 1 do APidList.Objects[i].Free;
APidList.Free;
ATree.Items.EndUpdate;
end;
end;
比起上次的方法,除了效率外,我觉得这次的方法代码也更为简洁点,没有用到什么栈结构;也不用什么RootFilterText来过滤根节点了。它能得出哪些是根节点(对于一些丢失父节点的节点,也能自动被处理成根节点),这是我觉得比较好的地方。