treeview改用DXTREELIST(CXTREELIST)的问题! ( 积分: 100 )

  • 主题发起人 主题发起人 LJH1978
  • 开始时间 开始时间
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的,应该做那些修改?
谢谢!
 
工作挺忙,抽空说两句:
1 这不是二分查找,用的是tstringList封装好的indexOf()顺序查找,你可以查看其vcl源码;如果数据有规律,二分查找更快,你可以自己写一个函数MyIndexOf()来代替你程序中的indexOf()函数
2 程序中所有Pointer(0)等都可以用nil替换,因为我看代码中没有对节点的指针data属性进行操作;
但以上统统都是题外话,和你程序的速度没什么关系。

如果改用cxtreelist的话,简单的说下,如果有疑问,有空再说。

(Node: TcxTreelistNode)
if iParentID = 0 then // 根节点
begin
Node := cxtreelist.addNode(nil,nil,nil,tlamAddChild);//函数声明看帮助
Node.StateIndex := iID;
Node.values:= sCaption //values中i是什么意思,我想你应该知道吧
List.AddObject(IntToStr(iID),Node);
end

if iIndex <> -1 then
begin
Node := cxtreelist.addNode(nil,
TcxTreeListNode(List.Objects[iIndex]),nil,tlamAddChild);
Node.StateIndex := iID;
Node.values:= sCaption;
List.AddObject(IntToStr(iID),Node);
end
 
晕,只能出现一条记录?

是不是和LIST有关?

另外觉得CXTREELIST要复杂得多
但DXTREELIST中不能用addNode
只有ADD,有什么变通的办法吗?
 
利用node.data属性来存储数据
procedure TForm_MediaAdm.TV_MediaTypeLoadTree(Sender: TMTreeView;
Node: TTreeNode; DataSet: TDataSet);
var
TreeData : pMediaType;
begin
if Assigned(Node) then
begin
New(TreeData);
Self.MediaADM.GainMediaType(TreeData^,DataSet);
Node.Data := TreeData;
end;
end;

procedure TForm_MediaAdm.TV_MediaTypeDeletion(Sender: TObject;
Node: TTreeNode);
var
TreeData : PMediaType;
begin
if Assigned(Node.Data) then
begin
TreeData := Node.Data;
Dispose(TreeData);
end;
end;
 
哦,原来 if Self.Tag <> 1 then break;这句注释掉就行
但更大的问题出来了,地区3501条代码,用TREEVIEW只要0.8秒,用CXTREELIST却要用18秒,不知怎么回事,要如何优化?
 
不好意思,来迟了。
cxdbtreelist没用过,公司几乎清一色cxtreelist;
cxtreelist非常不错,无论是功能,性能,美观都很刁的。
用CXTREELIST却要用18秒?不大可能吧,把你的完整代码贴出来,我想看看是怎么回事
 
不好意思,今天早上才看到消息
找到具体原因了,原来没加BeginUpdate及endupdate

最后地区3501条数据,普通TREEVIEW用1687MS,cxtreelist为1094ms,速度要快很多,对一次加载能达到这种速度,还是比较满意了,再次感谢大侠!
 
多人接受答案了。
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
503
import
I
后退
顶部