200分!如何把TStringList按树形结构显示在Treeview中?(200分)

  • 主题发起人 主题发起人 dage111
  • 开始时间 开始时间
D

dage111

Unregistered / Unconfirmed
GUEST, unregistred user!
我有一个表格,其中code的格式是0001,0002,00010001,00020001,00010001001(四位为一段),其中00010001是0001的子节点,000100010001是00010001的子节点。如何把strl中的数据按树形结构在treeview中显示出来?


下面是TStringList数据读取程序代码片段:
DS: TADODataSet;
strl:TStringList;


DS.CommandText := 'select code,name from table';
DS.Open;
strl.Clear;
while not DS.Eof do begin
strl.Add(DS.fieldbyname('name').AsString + '=' + DS.fieldbyname('code').AsString);
DS.Next;
end;
DS.First;
DS.Close;

要求:
1、代码片段里的str1已经读取完毕,在接下来的过程中不允许再进行数据库操作,只可以使用已经读取的str1来进行树形排列。
2、在treeview中树形显示。
 
循环STR1再一个个判断并分别加到TreeView,
 
procedure TForm1.FormCreate(Sender: TObject);
var
temp1,temp2:string;
begin
mmo1.Clear;
ds1.CommandText := 'select code,name from codetable order by code';
ds1.Open;
while not ds1.Eof do
begin
temp1 := ds1.fieldbyname('name').AsString;
temp2 := ds1.fieldbyname('code').AsString;
case Length(temp2) of
4: mmo1.Lines.Add(temp1+'='+temp2);
8: mmo1.Lines.Add(' '+temp1+'='+temp2);
12:mmo1.Lines.Add(' '+temp1+'='+temp2);
16:mmo1.Lines.Add(' '+temp1+'='+temp2);
end;
ds1.Next;
end;
ds1.First;
ds1.Close;
mmo1.Lines.SaveToFile('c:/q.txt');
tv1.LoadFromFile('c:/q.txt');
end;
 
把mmo改为tstringlist即可,tv1就是treeview啦.我觉得应该把 +temp1+'=' 去掉就美观点.
 
感谢jxgxy,不过偶的要求是使用strl并且在treeview中树形显示。
这两点你的代码中都没有体现出来。
1、使用strl
2、在treeview中树形显示。
 
procedure TForm1.FormCreate(Sender: TObject);
var
temp1,temp2:string;
strl:TStringList;
begin
strl := TStringList.Create;
// strl.Clear;
ds1.CommandText := 'select code,name from codetable order by code';
ds1.Open;
while not ds1.Eof do
begin
temp1 := ds1.fieldbyname('name').AsString;
temp2 := ds1.fieldbyname('code').AsString;
case Length(temp2) of
4: strl.Add(temp1+'='+temp2);
8: strl.Add(' '+temp1+'='+temp2);
12:strl.Add(' '+temp1+'='+temp2);
16:strl.Add(' '+temp1+'='+temp2);
end;
ds1.Next;
end;
ds1.First;
ds1.Close;
strl.SaveToFile('c:/q.txt');
tv1.LoadFromFile('c:/q.txt');
strl.Free;
end;




tv1就是treeview,名字你自已可以改吧.
 
很有道理, 顶顶!!!!!!!11
 
function pos1(s1,s2: string): boolean;
var i: integer;
begin
i:=pos('=',s1);
delete(s1,1,i);
result:= pos(s1,s2)=1;
end;

DS.CommandText := 'select code,name from table order by code';
DS.Open;
strl.Clear;
tv1.items.clear;
node:=nil;
while not DS.Eof do begin
while true do
begin
if node=nil then
begin
node:=tv1.items.add(nil,DS.fieldbyname('name').AsString + '=' + DS.fieldbyname('code').AsString);
break;
end;

if pos1(node.text,DS.fieldbyname('code').AsString) then
begin
node:=tv1.items.AddChild(node,DS.fieldbyname('name').AsString + '=' + DS.fieldbyname('code').AsString);
break;
end;

if node.level<>0 then
node:=Node.Parent
else begin
node:=tv1.items.add(nil,DS.fieldbyname('name').AsString + '=' + DS.fieldbyname('code').AsString);
break;
end;
end;

DS.Next;
end;
DS.First;
DS.Close;
 
觉得有意思,添加到树上结点的程序帮你做出来了。
procedure TForm1.AddTree(TreeInfo: TStringList);
function AddNode(ParentNode:TTreeNode;NewText:string):TTreeNode;
begin
while Assigned(ParentNode) do
begin
if Pos(ParentNode.Text,NewText)>0 then
Break;
ParentNode:=ParentNode.Parent;
end;
Result:=tv1.Items.AddChild(ParentNode,NewText);
end;
var
i:integer;
ParentNode:TTreeNode;
begin
TreeInfo.Sort;
ParentNode:=nil;
for i := 0 to TreeInfo.Count-1 do
ParentNode:=AddNode(ParentNode,TreeInfo);
end;

procedure TForm1.btn1Click(Sender: TObject);
var
loList:TStringList;
begin
tv1.Items.Clear;
loList:=TStringList.Create;
try
loList.Text:=mmo1.Lines.Text;
AddTree(loList);
finally
loList.Free;
end;
end;
 
to dang
你代码里的mmo1.Lines.Text是什么你没交代清楚,而且没有使用我的str1。

题目的意思是:str1已经读取完毕,在接下来的过程中不可以再进行数据库操作,只可以使用已经读取的str1来进行树形排列。
 
为什么要先读到str1再进行树形排列, 不怕速度慢吗?
 
就是想找一个速度快的算法啊。
 
为什么非得要用TreeView
VirtualStringTree,dxDBTreeList 等三方控件都可以实现这种功能!
效率优先!!
 
我可能有点没说清楚吧,这样吧,再变一下,写一个函数给你调用,我那是测试用的代码全都帖上去了。
参数TreeInfo就是你已经组织好的 strl:TStringList,你直接调用AddTree就行了。
程序的算法方面应是最优的了。
procedure AddTree(MyTree:TTreeView; TreeInfo: TStringList);
function AddNode(ParentNode:TTreeNode;NewText:string):TTreeNode;
begin
while Assigned(ParentNode) do
begin
if Pos(ParentNode.Text,NewText)>0 then
Break;
ParentNode:=ParentNode.Parent;
end;
Result:=MyTree.Items.AddChild(ParentNode,NewText);
end;
var
i:integer;
ParentNode:TTreeNode;
begin
MyTree.Items.Clear;
TreeInfo.Sort;
ParentNode:=nil;
for i := 0 to TreeInfo.Count-1 do
ParentNode:=AddNode(ParentNode,TreeInfo);
end;
 
to danng,
你的程序应该不完整吧。你用这个试一下看
procedure TForm1.Button1Click(Sender: TObject);
var
strl:TStringList;
begin

strl := TStringList.Create;
strl.Clear;
strl.Add('汽车=0001');
strl.Add('飞机=00010001');
strl.Add('坦克=00010002');
strl.Add('马甲=0002');
strl.Add('蚂蚁=0002001');
strl.Add('蜻蜓=0002002');
AddTree(TreeView1,strl);
end;
 
你的意思是想只显示名称不显示ID吧,刚才没看清楚,花了点时间再跟你写了一个,但为了效率更好,要你更改一下字符串列表的格式,如:
strl.Add('0001=汽车');
strl.Add('00010001=飞机');
strl.Add('00010002=坦克');

先要在单元单作一个定义
type
NodeRec=record
ID:string;
Name:string;
end;
PNodeRce=^NodeRec;

procedure TForm1.AddTree(MyTree:TTreeView; TreeInfo: TStringList);
var
i:integer;
ParentNode:TTreeNode;
IDList:TStringList;
function AddNode(poParentNode:TTreeNode;NewText:string):TTreeNode;
var
NodeRce:PNodeRce;
begin
while Assigned(poParentNode) do
begin
if Assigned(poParentNode.Data) and (Pos(PNodeRce(poParentNode.Data).ID,NewText)>0) then
Break;
poParentNode:=poParentNode.Parent;
end;
New(NodeRce);
NodeRce.ID:=NewText;
NodeRce.Name:=TreeInfo.Values[NewText];
Result:=MyTree.Items.AddChildObject(poParentNode,NodeRce.Name,NodeRce);
end;
begin
MyTree.Items.Clear;
IDList:=TStringList.Create;
try
for i := 0 to TreeInfo.Count-1 do
IDList.Add(TreeInfo.Names);
TreeInfo.Sort;
ParentNode:=nil;
for i := 0 to TreeInfo.Count-1 do
ParentNode:=AddNode(ParentNode,TreeInfo.Names);
finally
IDList.Free;
end;
end;

另外还需要你在TTreeView的OnDeletion事件中定一句释放内存的语句,如:
procedure TForm1.tv1Deletion(Sender: TObject; Node: TTreeNode);
begin
if Assigned(Node.Data) then
Dispose(PNodeRce(Node.Data));
end;
 
VirtualStringTree,dxDBTreeList比TreeView效率高么?
 
感谢danng。
 
后退
顶部