L
LJH1978
Unregistered / Unconfirmed
GUEST, unregistred user!
procedure TfrmTestSpeedMain.LoadTreeOf_7;
var
List :TStringList;
iIndex, iParentID, iID, iFail :integer;
sCaption :string;
Node : TTreeNode;
begin
// 循环一次加到树上,加子时查树,使用内存列表 非常快
// 数据集必须是排序的,否则子节点加不完整
{
算法出处说明: 根据数据表的内容生成TreeView树状结构,通常的做法就是从顶级开始,
然后逐项递归查询遍历生成。这种方法在实现上容易做到,也很容易想到,但是效率比
较低,因为数据库的检索(SQL语句需要解释执行,而且是对数据库文件进行操作)还是比
较耗时的,尤其是树的层次较多,节点较多的情况。这里我要介绍的方法是以空间换取
时间,只进行一次数据库检索,提取出全部数据,然后一次生成TreeView树状结构。
通过SQL语句,让返回的记录按照父节点ID、节点ID进行排序,这样保证每次当前要添加
的节点记录的父节点都已经添加到了TreeView树中,剩下的工作就是如何在TreeView树中
找到父节点。这里我采用了一个排序的TStringList列表,通过排序列表采用二分查找的
快速性能,就能够很快地查找到当前要添加节点的父节点,从而插入到TreeView树的正确
位置。
}
List := TStringList.Create;
try
List.Sorted := True; // 内存数据 排序加快查询
AdoQuery.Sql.Text := 'select top ' + IntToStr(fLoadCount) +
' FID,FParentID,FCaption from '+ TreeTable;
if chkOrderBy.Checked then
AdoQuery.Sql.Text := AdoQuery.Sql.Text + ' order by FParentID,FCaption';
AdoQuery.Active := True;
iFail := 0;
while not AdoQuery.Eof do
begin
iParentID := AdoQuery.FieldByName('FParentID').AsInteger;
iID := AdoQuery.FieldByName('FID').AsInteger;
sCaption := AdoQuery.FieldByName('FCaption').AsString;
if iParentID = 0 then // 根节点
begin
Node := tv.Items.AddObject(nil,sCaption ,Pointer(0));
Node.StateIndex := iID;
List.AddObject(IntToStr(iID),Node);
end
else // 子节点
begin
iIndex := List.IndexOf(IntToStr(iParentID)); // 查询当前记录的父是否加到节点上了
//ToDo: 排序了,应父节点都加上去了吧?
if iIndex <> -1 then
begin
Node := tv.Items.AddChildObject(TTreeNode(List.Objects[iIndex]),
sCaption ,Pointer(iID));
Node.StateIndex := iID;
List.AddObject(IntToStr(iID),Node);
end
else
Inc(iFail);
end;
if Self.Tag <> 1 then break;
lblLog.Caption := '正在加载... ' + IntToStr((tv.Items.Count+1)*100 div fLoadCount) + ' %';
Application.ProcessMessages;
AdoQuery.Next;
end;
if iFail >0 then
mLog.Lines.Add(' LoadTreeOf_7 存在不能连接的父子节点 数量:' +
IntToStr(iFail));
finally
List.Free;
end;
end;
这个一次性加载树速度是比较理想的了,可我用的是DEV公司的DXTREELIST(CXTREELIST)控件
DXTREELIST没有AddObject属性,如果我要将上述代码改成DXTREELIST的,应该做那些修改?
谢谢!
var
List :TStringList;
iIndex, iParentID, iID, iFail :integer;
sCaption :string;
Node : TTreeNode;
begin
// 循环一次加到树上,加子时查树,使用内存列表 非常快
// 数据集必须是排序的,否则子节点加不完整
{
算法出处说明: 根据数据表的内容生成TreeView树状结构,通常的做法就是从顶级开始,
然后逐项递归查询遍历生成。这种方法在实现上容易做到,也很容易想到,但是效率比
较低,因为数据库的检索(SQL语句需要解释执行,而且是对数据库文件进行操作)还是比
较耗时的,尤其是树的层次较多,节点较多的情况。这里我要介绍的方法是以空间换取
时间,只进行一次数据库检索,提取出全部数据,然后一次生成TreeView树状结构。
通过SQL语句,让返回的记录按照父节点ID、节点ID进行排序,这样保证每次当前要添加
的节点记录的父节点都已经添加到了TreeView树中,剩下的工作就是如何在TreeView树中
找到父节点。这里我采用了一个排序的TStringList列表,通过排序列表采用二分查找的
快速性能,就能够很快地查找到当前要添加节点的父节点,从而插入到TreeView树的正确
位置。
}
List := TStringList.Create;
try
List.Sorted := True; // 内存数据 排序加快查询
AdoQuery.Sql.Text := 'select top ' + IntToStr(fLoadCount) +
' FID,FParentID,FCaption from '+ TreeTable;
if chkOrderBy.Checked then
AdoQuery.Sql.Text := AdoQuery.Sql.Text + ' order by FParentID,FCaption';
AdoQuery.Active := True;
iFail := 0;
while not AdoQuery.Eof do
begin
iParentID := AdoQuery.FieldByName('FParentID').AsInteger;
iID := AdoQuery.FieldByName('FID').AsInteger;
sCaption := AdoQuery.FieldByName('FCaption').AsString;
if iParentID = 0 then // 根节点
begin
Node := tv.Items.AddObject(nil,sCaption ,Pointer(0));
Node.StateIndex := iID;
List.AddObject(IntToStr(iID),Node);
end
else // 子节点
begin
iIndex := List.IndexOf(IntToStr(iParentID)); // 查询当前记录的父是否加到节点上了
//ToDo: 排序了,应父节点都加上去了吧?
if iIndex <> -1 then
begin
Node := tv.Items.AddChildObject(TTreeNode(List.Objects[iIndex]),
sCaption ,Pointer(iID));
Node.StateIndex := iID;
List.AddObject(IntToStr(iID),Node);
end
else
Inc(iFail);
end;
if Self.Tag <> 1 then break;
lblLog.Caption := '正在加载... ' + IntToStr((tv.Items.Count+1)*100 div fLoadCount) + ' %';
Application.ProcessMessages;
AdoQuery.Next;
end;
if iFail >0 then
mLog.Lines.Add(' LoadTreeOf_7 存在不能连接的父子节点 数量:' +
IntToStr(iFail));
finally
List.Free;
end;
end;
这个一次性加载树速度是比较理想的了,可我用的是DEV公司的DXTREELIST(CXTREELIST)控件
DXTREELIST没有AddObject属性,如果我要将上述代码改成DXTREELIST的,应该做那些修改?
谢谢!