一:TreeView.Items[0].Expanded := True; // 展开第一个节点 
 
二:TreeView.Items[0].Item[0].Selected := True; // 移动到第一个节点的第一个子节点   
 
找当前节点的下一个节点,按序号找如下: 
 
if treeview1.Selected.GetNext<>nil then 
 
treeview1.Selected.GetNext.Selected:=true; 
 
TreeView1.SetFocus; 
 

找当前节点的下一个同层兄弟如下: 
 
if treeview1.Selected.getNextSibling<>nil then 
 
treeview1.Selected.getNextSibling.Selected:=true; 
 
TreeView1.SetFocus; 
 
TreeView.Selected.getPrevSibling  //当前选中节点的上一个兄弟节点 
 
TreeView.Selected.Parent          //  当前选中节点的父节点   
 

getfirstchild是跳到该节点子结点中的第一个 
 
getlastchild是跳到该节点子结点中的最后一个 
 

如果你是想跳到同层兄弟结点的第一个 
 
if treeview1.selected.parent<>nil then 
 
treeview1.selected.parent.getfirstchild.selected:=true 
 
else 
 
treeview1.items.item[0].selected:=true; 
 

如果你是想跳到同层兄弟结点的最后一个 
 
if treeview1.selected.parent<>nil then 
 
treeview1.selected.parent.getlastchild.selected:=true 
 
else 
 
treeview1.Items.Item[treeview1.Items.Count-1].Selected:=true; 
 
TreeView的使用方法 
 


基本信息: 
 
TreeView 是一个显示树型结构的控件,每一个节点都是一个新类, 
 
使用具有代表性 
 
每个节点都有四个值: 
 
TEXT:显示文字 Image Index:显示图形序号 
 
Selected Index: 
 
State Index: 
 

(1)建立目录项(本例中使用的TREEVIEW名称为:TvwTips) 
 

增加根目录下的节点:(节点) 
 
var 
 
CatNode : TTreeNode; //先建立一个TREEVIEW使用的子对象 
 
begin 
 
TvwTips.SetFocus; //将焦点置到这个TREEVIEW控件上 
 
{ 在根标题下建立一个新的子标题 } 
 
CatNode := TvwTips.Items.AddChild( 
 
TvwTips.Items.GetFirstNode,'New Category' ); 
 
CatNode.ImageIndex := 1; 
 
CatNode.SelectedIndex := 2; 
 
CatNode.EditText; { 允许用户改变这个标题 } 
 
end; 
 

增加下一级目录(内容): 
 
var 
 
ParentNode, TipNode : TTreeNode; //先建立TREEVIEW使用 
 
的子对象 
 
VersionNum : Integer; 
 
begin 
 
TvwTips.SetFocus; //将焦点置到这个TREEVIEW控件上 
 
VersionNum := TMenuItem( Sender ).Tag; { Ver num of new tip } 
 
ParentNode := TvwTips.Selected; { 取出当前的选中节点 } 
 
if ParentNode.Level = nlTip then{ Parent cannot be a tip node } 
 
ParentNode := TvwTips.Selected.Parent; 
 

TipNode := TvwTips.Items.AddChildObject( ParentNode,'New 
 
Subject',Pointer( VersionNum ) ); 
 
TipNode.ImageIndex := 3; { Normal tip bitmap } 
 
TipNode.SelectedIndex := 4; { Highlighted tip bitmap } 
 
TipNode.MakeVisible; { Move new tip node into view } 
 
TipNode.EditText; { Immediately allow user to edit subject } 
 
EnableTreeViewFunctions( TipNode.Level ); 
 
RtfTip.Clear; 
 
RtfTip.Modified := False; 
 
end; 
 

(2)说明 
 
TvwTips.Items.GetFirstNode 返回TREEVIEW的第一个节点,函数类型为 
 
:TTreeNode 
 
TvwTips.Items.Count 返回当前TreeView的全部节点数,整数 
 
TvwTips.Selected.Level 返回当前选中节点的在目录树中的级别, 
 
根目录为0 
 
TvwTips.Selected.Parent 返回当前选中节点上级节点,函数类型为 
 
:TTreeNode 
 

三、下面这段程序是用TREEVIEW连数据库及一些操作: 
 
unit bmzd; 
 

interface 
 

uses 
 
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, 
 
 StdCtrls, ComCtrls, Db, DBTables, ImgList, Buttons, ExtCtrls, Grids, 
 
 DBGrids; 
 

type 
 
 Tfrmbmzd = class(TForm) 
 
   Panel1: TPanel; 
 
   cmd_new: TBitBtn; 
 
   cmd_delete: TBitBtn; 
 
   cmd_exit: TBitBtn; 
 
   tvwcode: TTreeView; 
 
   ScrollBox1: TScrollBox; 
 
   GroupBox2: TGroupBox; 
 
   Label3: TLabel; 
 
   Label2: TLabel; 
 
   Label1: TLabel; 
 
   Label4: TLabel; 
 
   Label5: TLabel; 
 
   Edit2: TEdit; 
 
   Edit3: TEdit; 
 
   Edit4: TEdit; 
 
   Edit5: TEdit; 
 
   ImageList1: TImageList; 
 
   Edit1: TEdit; 
 
   cmd_save: TBitBtn; 
 
   cmd_update: TBitBtn; 
 
   procedure FormShow(Sender: TObject); 
 
   procedure FormClose(Sender: TObject; var Action: TCloseAction); 
 
   procedure cmd_newClick(Sender: TObject); 
 
   procedure cmd_deleteClick(Sender: TObject); 
 
   procedure Edit2KeyPress(Sender: TObject; var Key: Char); 
 
   procedure tvwcodeChange(Sender: TObject; Node: TTreeNode); 
 
   procedure cmd_updateClick(Sender: TObject); 
 
   procedure BitBtn2Click(Sender: TObject); 
 
   procedure tvwcodeClick(Sender: TObject); 
 
 private 
 
   { Private declarations } 
 
     function LoadCode(crTbl:TDBDataSet):Integer; 
 
function GetLevel(sFormat,sCode:String):Integer; 
 

 public 
 
   { Public declarations } 
 
 end; 
 

var 
 
 frmbmzd: Tfrmbmzd; 
 
 ii:integer; 
 
 tv:ttreenode; 
 
 const 
 
SCodeFormat = '222222';   //科目代码结构 
 
SFirstNodeTxt   = '部门分类'; 
 

implementation 
 

uses dm; 
 


{$R *.DFM} 
 

function tfrmbmzd.LoadCode(crTbl:TDBDataSet):Integer; 
 
var NowID,sName,ShowTxt:String; 
 
i,Level:Integer; 
 
MyNode:array[0..6]of TTreeNode; 
 
//保存各级节点,最长支持6级(重点) 
 
begin 
 
Screen.Cursor:=crHourGlass; 
 
Level:=0; 
 
With frmdm.tabbm do 
 
begin 
 
try 
 
if not Active then Open; 
 
First; 
 
tvwCode.Items.Clear; 
 
//以下是增加第一项 
 
MyNode[Level]:=tvwCode.Items.Add 
 
(tvwCode.TopItem,SFirstNodeTxt); 
 
MyNode[Level].ImageIndex:=0; 
 
MyNode[Level].SelectedIndex:=0; 
 
//以上是增加第一项 
 
While Not Eof do 
 
begin 
 
NowID:=Trim(FieldByName('bumeng_id').AsString); 
 
ShowTxt:=FieldByName('bumeng_name').AsString; 
 
Level:=GetLevel(SCodeFormat,NowID); 
 
//返回代码的级数 
 
//以下是增加子项 
 
//以下用上一级节点为父节点添加子节点 
 
if Level>0 then//确保代码符合标准 
 
begin 
 
  MyNode[Level]:=tvwCode.Items.AddChild 
 
(MyNode[Level-1],NowID+' '+ShowTxt); 
 
  MyNode[Level].ImageIndex:=1; 
 
 MyNode[Level].SelectedIndex:=2; 
 
end;   
 
//以上是增加子项 
 
Next; 
 
end; 
 
finally 
 
Close; 
 
end; 
 
end; 
 
MyNode[0].Expand(False);//将首节点展开 
 
Screen.Cursor:=crDefault; 
 
end; 
 
//以上函数将Code.db表中的科目代码和科目代码名称显示出来 
 

//下面函数的功能是返回一代码的级数, 
 
//参数sFormat传递科目代码结构; 
 
//参数sCode传递某一科目代码 
 
function tfrmbmzd.GetLevel 
 
(sFormat,sCode:String):Integer; 
 
var i,Level,iLen:Integer; 
 
begin 
 
Level:=-1;//如果代码不符合标准,则返回-1 
 
iLen:=0; 
 
if (sFormat<>'')and(sCode<>'')then 
 
for i:=1 to Length(sFormat) do 
 
begin 
 
iLen:=iLen+StrToInt(sFormat[i]); 
 
if Length(sCode)=iLen then 
 
begin 
 
  Level:=i; 
 
  Break; 
 
end; 
 
end; 
 
Result:=Level; 
 
end; 
 

procedure Tfrmbmzd.FormShow(Sender: TObject); 
 
begin 
 

if not frmdm.tabbm.active then frmdm.tabbm.Open; 
 
frmdm.tabbm.IndexFieldNames:='BUMENG_ID'; 
 
//按字段aCode排序(不要漏掉) 
 

LoadCode(frmdm.tabbm); 
 



end; 
 

procedure Tfrmbmzd.FormClose(Sender: TObject; var Action: TCloseAction); 
 
begin 
 
Action := caFree; 
 
end; 
 

procedure Tfrmbmzd.cmd_newClick(Sender: TObject); 
 
begin 
 
tvwcode.SetFocus ; 
 
if tvwcode.selected.AbsoluteIndex<>0 then 
 
begin 
 
cmd_delete.Enabled:=true; 
 
cmd_update.Enabled:=true; 
 
cmd_save.Enabled :=true; 
 
if not frmdm.tabbm.Active then frmdm.tabbm.Open; 
 

edit1.text:=frmdm.tabbm.Fields[0].asstring; 
 
end; 
 
tvwcode.SetFocus ; 
 
tvwcode.Items.AddChild(tvwcode.selected,'新建部门'); 
 
if   tvwcode.Selected.HasChildren then 
 
begin 
 
if tvwcode.Selected.GetLastChild.index+1>9 then 
 
 edit2.text:=inttostr(tvwcode.Selected.GetLastChild.index+1) 
 
 else 
 
edit2.text:='0'+inttostr(tvwcode.Selected.GetLastChild.index+1); 
 
edit3.text:='新建部门'; 
 
edit2.Enabled:=true; 
 
edit3.Enabled:=true; 
 
end 
 
else 
 
begin 
 
edit2.text:='01'; 
 
edit3.text:='新建部门'; 
 
edit2.Enabled:=true; 
 
edit3.Enabled:=true; 
 
end; 
 
if not frmdm.tabbm.Active then frmdm.tabbm.Open; 
 
frmdm.tabbm.edit; 
 
frmdm.tabbm.Append; 
 
cmd_new.Enabled :=false; 
 
cmd_delete.Enabled :=false; 
 
cmd_update.Enabled :=false; 
 
cmd_save.Enabled :=true; 
 
//新建下级部门 
 

tvwcode.Selected.GetLastChild.Selected:=true; 
 
//设选择 
 
tv:=tvwcode.Selected ; 
 
tvwcode.autoExpand:=true; 
 
tvwcode.SetFocus ; 
 


end; 
 

procedure Tfrmbmzd.cmd_deleteClick(Sender: TObject); 
 
var 
 
I:integer; 
 
seno,setext:string; 
 
begin 
 
if tvwcode.Selected.HasChildren=true then 
 
begin 
 
application.messagebox('该部门包含下级,不能删除','提示',MB_OKCANCEL+mb_iconquestion ) ; 
 
end 
 
else 
 
begin 
 
if   application.messagebox('你确实要删除当前部门吗','提示',MB_OKCANCEL+mb_iconquestion )=IDOK then 
 
begin 
 
setext:=tvwcode.selected.text; 
 
i:=0; 
 
while setext[i] <> ' ' do 
 
begin 
 
I := I + 1; 
 
seno:=seno+setext[i]; 
 
end; 
 
if not frmdm.tabbm.Active then frmdm.tabbm.Open; 
 
frmdm.tabbm.setkey; 
 
frmdm.tabbm.Fields[0].asstring:=seno; 
 
if frmdm.tabbm.GotoKey then 
 
begin 
 
frmdm.tabbm.edit; 
 
frmdm.tabbm.Delete; 
 
end; 
 
tvwcode.Selected.Delete ; 
 
cmd_new.Enabled :=true; 
 
tvwcode.autoExpand:=true; 
 
 tvwcode.SetFocus ; 
 
end; 
 
end; 
 

end; 
 

procedure Tfrmbmzd.Edit2KeyPress(Sender: TObject; var Key: Char); 
 
begin 
 
if key  in ['0'..'9',Chr(vk_Back)]   then 
 

else 
 
begin 
 
key:=#0; 
 
application.messagebox('','',mb_ok); 
 

end; 
 
end; 
 

procedure Tfrmbmzd.tvwcodeChange(Sender: TObject; Node: TTreeNode); 
 
var 
 
i,lev:integer ; 
 
strr,seno,setext:string; 
 
begin 
 
if cmd_new.Enabled =true then 
 
begin 
 
if tvwcode.selected.AbsoluteIndex<>0   then 
 
begin 
 
cmd_delete.Enabled:=true; 
 
cmd_update.Enabled:=true; 
 
cmd_save.Enabled :=true; 
 
setext:=tvwcode.selected.text; 
 
i:=0; 
 
while setext[i] <> ' ' do 
 
begin 
 
I := I + 1; 
 
seno:=seno+setext[i]; 
 
end; 
 
if not frmdm.tabbm.Active then frmdm.tabbm.Open; 
 
frmdm.tabbm.setkey; 
 
frmdm.tabbm.Fields[0].asstring:=seno; 
 
frmdm.tabbm.GotoKey; 
 
strr:=''; 
 

case tvwcode.Selected.Level of 
 
2: strr:=copy(frmdm.tabbm.fields[0].asstring,1,2); 
 
3: strr:=copy(frmdm.tabbm.fields[0].asstring,1,4); 
 
 end; 
 
 edit1.text:=strr; 
 
//加上级编码 
 
edit3.text:=frmdm.tabbm.Fields[1].asstring; 
 
//本级编码 
 

edit2.text:=copy(frmdm.tabbm.fields[0].asstring,length(frmdm.tabbm.fields[0].asstring)-1,2); 
 

end 
 
else 
 
begin 
 
edit1.text :=''; 
 
edit2.text :=''; 
 
edit3.text :='部门分类'; 
 
cmd_delete.Enabled :=false; 
 
cmd_update.Enabled :=false; 
 
end; 
 
end; 
 
end; 
 


procedure Tfrmbmzd.cmd_updateClick(Sender: TObject); 
 
var 
 
i:integer; 
 
begin 
 
for i:=0 to ComponentCount-1  do 
 
begin 
 
if (Components[I]  is tedit ) then 
 
(Components[I]  as tedit).enabled:=false; 
 
end; 
 
for i:=0 to ComponentCount-1  do 
 
begin 
 
if (Components[I]  is tbitbtn ) then 
 
(Components[I]  as tbitbtn).enabled:=true; 
 
end; 
 
if tvwcode.Selected.AbsoluteIndex<>0 then 
 
begin 
 

if not frmdm.tabbm.Active  then frmdm.tabbm.Open; 
 
frmdm.tabbm.Edit; 
 
frmdm.tabbm.Fields[0].asstring:=edit1.text+edit2.text; 
 
frmdm.tabbm.Fields[1].asstring:=edit3.text; 
 
try 
 
frmdm.tabbm.Post; 
 
//表的保存 
 
except 
 
on edbengineerror do 
 
begin 
 
edit2.Enabled :=true; 
 
 application.messagebox('编号不能重复,请重新输入','提示',MB_OK+mb_iconquestion ) ; 
 
exit; 
 
end; 
 
 end; 
 
tvwcode.Selected.Text:=edit1.text+edit2.text+' '+edit3.text; 
 
tvwcode.SetFocus ; 
 
//修改树 
 
end; 
 

cmd_new.Enabled :=true; 
 
edit2.Enabled :=false; 
 
end; 
 

procedure Tfrmbmzd.BitBtn2Click(Sender: TObject); 
 
begin 
 
cmd_new.Enabled :=false; 
 
cmd_delete.Enabled :=false; 
 
edit2.enabled:=true; 
 
edit3.Enabled :=true; 
 

end; 
 

procedure Tfrmbmzd.tvwcodeClick(Sender: TObject); 
 
var 
 
i:integer; 
 
begin 
 
if cmd_new.Enabled =false then 
 
begin 
 
application.MessageBox('当前是修改状态,请单击保存按钮','提示',mb_ok); 
 
tv.Selected :=true; 
 
end; 
 
if  tvwcode.selected.AbsoluteIndex=0 then 
 
begin 
 
for i:=0 to ComponentCount-1  do 
 
begin 
 
if (Components[I]  is tedit ) then 
 
(Components[I]  as tedit).enabled:=false; 
 
end; 
 
for i:=0 to ComponentCount-1  do 
 
begin 
 
if (Components[I]  is tbitbtn ) then 
 
(Components[I]  as tbitbtn).enabled:=false; 
 
cmd_new.Enabled :=true; 
 
cmd_exit.Enabled :=true; 
 
end; 
 
end; 
 
end; 
 
end 
 

四、使用概述 
 
树形图(Treeview)是Win95下新增加的通用显示部件(Common Control,在COMCTL32.DLL中)之一,从Delphi2.0开始也增加了相应的控件Treeview,用于取代原Outline控件。由于树形图结构较复杂,使用起来常不知如何下手。这里就使用中的一些问题作些介绍。 
 
   Treeview用于显示按照树形结构进行组织的数据,这在实际当中用途还是比较广泛的,如计算机中的文件系统(Windows95中的资源管理器)、企业或公司的组成结构等等。Treeview控件中一个树形图由节点(TreeNode)和连接线组成。TtreeNode是TTreeview的基本组成单元。一个树的节点又包含文本(Text)和数据(Data)。Text为String类,Data则为无定形指针(Untyped Pointer),可以指向一个与节点相联系的数据结构。 
 
  每一个节点下子节点形成这一节点的Items属性,当前节点有一个唯一的Index(TreeNode的Index属性),用于说明子节点在Items中的位置,每一个节点下的子节点是顺序编号的,第一个是0,第二个是1,依次类推。用IndexOf方法获得子节点的顺序,绝对顺序(AbsoluteIndex)则是指从Treeview第一个项开始的顺序值,第一个是0,如此推下去。Item属性则根据Index的值返回当前节点的第Index个子节点。Count则表明属于此项的所有子节点的数量。用MoveTo方法将Item由一个位置移到另一个位置。 
 
  Expanded属性表明是否所有的子项都全部展开(包括子项的子项),为True表示全部展开。IsVisible属性表明一个项是否在树中能被看到,如果树全部展开那么这个Item是肯定可以被看到。HasChildren属性表明一个项是否有子项。 GetFirstChild, GetLastChild, GetPrevChild, and GetNextChild分别返回当前项子项的第一个、最后一个和前一个、后一个项。GetNextSibling and GetPrevSibling则返回在同一Level下的下一个和上一个项。GetNextVisible and GetPrevVisible则返回能看得到的下一个和上一个项。如果一个节点有Parent,则HasAsParent方法返回True. Parent为当前项的父项。Focused属性确定焦点是否落在此节点上,被Focus时会一个标准的方框围住。很显然,只有一个节点会被聚焦。 Selected属性表明一个节点是否被选中,同样只有一个节点会被选中。DropTarget属性表明节点在拖动操作中是源还是目标。 
 
1.添加、删除、修改节点: 
 
静态的方法可以在设计时通过Items的编辑器设置各节点的内容。 
 
在添加和删除前必须保证有节点被选中(Treeview.Selected = nil) 
 
用AddFirst, AddFirstChild, AddChild等先添加根节点,如Treeview.Items.AddFirst( nil, 'Root'); 
 
然后以此为基础,添加此项的子节点。 
 

删除节点 
 
Treeview.Selected.Delete 
 
编辑节点内容 
 
Treeview.Selected.EditText 
 
注意:由于根节点没有父节点 (TTreeNode.Parent= nil) 
 
此外,在大批量添加数据到Treeview中时最好使用 
 
  TreeView.Items.BeginUpdate; 
 
  添加节点 
 
  TreeView.Items.EndUpdate 
 
这样能加快显示速度。 
 

2.在节点上添加图象 
 
Treeview中几个与图象相关的属性: 
 
  SelectedIndex:当节点被选中时在TimageList 中选什么样的图象 
 
  OverlayIndex:选那副图象作为掩图(一幅图象透明地显示在另一幅图象的前面),比如一个节点不可用时加一副X图象在其前面。 
 
  ImageIndex:在常态时选用的图的序号 
 
  StateIndex: 在StateImages这个ImageList中对应的序号,-1时不显示图象 
 
  比较典型的,象在文件管理器中的所显示的一样,Treeview控件在节点之前也可以显示图象。在Form中放置一ImageList控件,加入几个图片,分别被Index为0,1,…在Treeview的Image属性项填入你所加入的ImageList的控件名称。TreeNode的ImageIndex表示节点未被选中时(Selected=nil)的图片序号,SelectedIndex表示节点被选中时图片序号。 
 

3.关于Level 
 
Level的概念可以用下图表示: 
 
Level0   Level1 Level2 
 

4.排序 
 
SortType决定什么时候进行排序; 
 
TreeView.AlphaSort对节点进行排序,如果不能满足要求,你可以定义自己的CustomSort方法。 
 
5.Drag&Drop操作,与标准的拖放操作使用方法一样。 
 

五、一个例子: 
 
 首先,在库的构建上要有一定策略以下几个字段非常重要: 
 
'codeID'      代码集名称 (例如:'AB') 
 
'code'        节点代码   (例如:'新疆'节点的代码为'65','乌鲁木齐'的节点代码为'6501'等) 
 
'description' 节点描述   (例如:如上面的'新疆'、'乌鲁木齐'等) 
 
'pptr'        父节点代码 (例如:'乌鲁木齐'节点的父代码为'65',最高层节点的父节点代码可同其代码集,例如:'新疆'的父节点为                              'AB') 
 
'cptr'        子节点标识 (例如:该节点是否有下级节点,有则取值'1',没有则取值'0') 
 



建立树由两部分构成: 
 

procedure TForm1.FormActivate(Sender: TObject); 
 
var 
 
 code_ID,new_sql,node_text,table_name:string; 
 
 new_node:Ttreenode; 
 
begin 
 

//要传递的参数 
 
code_ID:='AB'; 
 
table_name:='sr_codeitem'; 
 

//******** 
 
treeview1.Items.BeginUpdate; 
 

//清空所有项目 
 
treeview1.Items.Clear; 
 


new_sql:='select * from '+ table_name + ' where codeID='+''''+code_ID+'''' 
 
        + ' and '+'pptr='+''''+code_ID+''''; 
 


//数据集中先筛选出所有要增加节点 
 
with dm1.Query1 do 
 
begin 
 
  close; 
 
  sql.Clear; 
 
  sql.Add(new_sql); 
 
  open; 
 
  //增加第一层节点 
 
  while not eof do 
 
    begin 
 
      node_text:=fieldbyname('code').asstring; 
 
      node_text:=node_text+'   '+fieldbyname('description').asstring; 
 
      new_node:=treeview1.Items.add(nil,node_text); 
 
      new_node.HasChildren:=true; 
 
      next; 
 
    end;//end while 
 
end;//end with 
 

treeview1.Items.EndUpdate; 
 
end; 
 

procedure TForm1.TreeView1Expanding(Sender: TObject; Node: TTreeNode; 
 
var AllowExpansion: Boolean); 
 
var 
 
 new_sql,node_text,child_text,code_ID,table_ID:string; 
 
 child_node:Ttreenode; 
 
begin 
 
//获取参数 
 
code_ID:='AB'; 
 
table_ID:='sr_codeitem'; 
 

treeview1.Items.BeginUpdate; 
 
node_text:=node.Text; 
 
//截取所点击节点的code 
 
node_text:=copy(node_text,1,pos(' ',node_text)-1); 
 
with dm1.Query1 do 
 
begin 
 
  close; 
 
  sql.Clear; 
 
  new_sql:='select * from '+table_ID+' where pptr='+''''+node_text+'''' + ' and codeID=' 
 
            +''''+code_ID+''''; 
 
  sql.Add(new_sql); 
 
  open;//定位所点的项 
 
  //清除原来的下级节点 
 
  node.DeleteChildren; 
 
  while not eof do 
 
     begin//增加下级节点 
 
       child_text:=fieldbyname('code').asstring+'   '+fieldbyname('description').asstring; 
 
       child_node:=treeview1.Items.AddChild(node,child_text); 
 
       if fieldbyname('cptr').asstring='1' then 
 
          child_node.HasChildren:=true; 
 
          next; 
 
     end;//end while 
 

end;//end with 
 
treeview1.Items.EndUpdate; 
 
end; 
 
 第二部分:在 treeview 的onExpanding 事件中添加如下代码 
 
procedure TForm1.TreeView1Expanding(Sender: TObject; Node: TTreeNode; 
 
var AllowExpansion: Boolean); 
 
var 
 
 new_sql,node_text,child_text,code_ID,table_ID:string; 
 
 child_node:Ttreenode; 
 
begin 
 
//获取参数 
 
code_ID:='AB'; 
 
table_ID:='sr_codeitem'; 
 

treeview1.Items.BeginUpdate; 
 
node_text:=node.Text; 
 
//截取所点击节点的code 
 
node_text:=copy(node_text,1,pos(' ',node_text)-1); 
 
with dm1.Query1 do 
 
begin 
 
  close; 
 
  sql.Clear; 
 
  new_sql:='select * from '+table_ID+' where pptr='+''''+node_text+'''' + ' and codeID=' 
 
            +''''+code_ID+''''; 
 
  sql.Add(new_sql); 
 
  open;//定位所点的项 
 
  //清除原来的下级节点 
 
  node.DeleteChildren; 
 
  while not eof do 
 
     begin//增加下级节点 
 
       child_text:=fieldbyname('code').asstring+'   '+fieldbyname('description').asstring; 
 
       child_node:=treeview1.Items.AddChild(node,child_text); 
 
       if fieldbyname('cptr').asstring='1' then 
 
          child_node.HasChildren:=true; 
 
          next; 
 
     end;//end while 
 

end;//end with 
 
treeview1.Items.EndUpdate; 
 
end;   
 

六、让我们一个一个来回答: 
 
第一个:取出节点的text属性值,赋给Richedit的Lines.text即可; 
 
例如: self.RichEdit1.Lines.text:= self.Treeview1.selected.text; 
 
第二个:TtreeView控件有函数保存和载入树的结构到文件 
 
例如:self.Treeview1.SaveToFile('文件名');//保存结构 
 
     self.TreeView1.LoadFromFile('文件名');//载入结构 
 
第三个:TreeView的每个节点都有ItemID(句柄),AbsoluteIndex(相对于树头节点的索引位置), 
 
Index(在当前层的位置),Level(本节点的层数)通过访问这些可以知道其位置; 
 
例如:self.TtreeView1.selected.ItemID;//返回句柄 
 
    self.TreeView1.selected.Level;//返回层数 
 
    self.TreeView1.Items.count//返回所有节点的个数; 
 
**寻找某一个节点的话,就只有写一个循环来遍历整个树,直到找到符合条件的节点为止, 
 
关于查找节点的代码我也在想,先参考上面同志们的回答吧; 
 

??**为某个节点加上子节点,例如: 
 
var NewNode:TTreeNode; 
 
begin 
 
NewNode:=self.Treeview1.Items.addChild(self.Treeview1.Items[3],'新的字节点'); 
 
//为self.Treeview1.Items[3]加上一个字节点,标签是'新的字节点', 
 
//还有其他的ADD方法,可以查找Delphi帮助 
 
//然后可以给刚加上去的子节点赋值; 
 
NewNode.ImageIndex:=n; 
 
NewNode.SelectedIndex:=M; 
 
NewNode.Data:=X;//注意X是一个指针类型;关于这方面的帮助 
 
//可以找一下TTreeNode.Data 属性例子 
 
end; 
 
??**想选中某个节点:self.TreeView1.Items[n].selected:=true;//这样就选中了 
 
??**展开某节点就容易了:self.TreeView1.Items[n].Expand;//展开啦! 
 
//想合上就用Collapse(Recurse: Boolean)函数, 
 
总之呢,去查一下TtreeNode的帮助吧! 
 
??**清除某节点下的所有子节点,用DeleteChildren是没错的,例如: 
 
self.Treeview1.Items[n].DeleteChildren;//OK,下面都没了! 
 

七、query1.close; 
 
query1.sql.clear; 
 
query1.sql.add('select * from t08 order by t0801'); 
 
try 
 
  query1.open; 
 
except 
 
  on e:exception do 
 
  begin 
 
     application.MessageBox(pchar('打开数据库文件失败!'+#13+#13+e.Message),'错误信息',16); 
 
     close; 
 
     exit; 
 
  end; 
 
end; 
 
//创建结构树 
 
while not query1.eof do 
 
begin 
 
   s:=trim(query1.fields[0].asstring); 
 
   case length(s) of 
 
   2:begin 
 
        tv1.Selected:=tv1.items.add(nil,trim(query1.fields[1].asstring)); 
 
        tv2.Selected:=tv2.items.add(nil,trim(query1.fields[0].asstring)); 
 
     end; 
 
   4:begin 
 
        p1:=tv1.items.addchild(tv1.Selected,trim(query1.fields[1].asstring)); 
 
        p2:=tv2.items.addchild(tv2.Selected,trim(query1.fields[0].asstring)); 
 
     end; 
 
   6:begin 
 
        tv1.Items.addchild(p1,trim(query1.fields[1].asstring)); 
 
        tv2.Items.addchild(p2,trim(query1.fields[0].asstring)); 
 
     end; 
 
   end; 
 
   query1.next; 
 
end; 
 
query1.close; 
 
if tv1.Items.Count>0 then 
 
begin 
 
 tv1.Selected:=tv1.Items[0]; 
 
 tv1.Selected.Expand(true); 
 
end; 
 
tv1.OnClick(self);   
 
八、clear速度慢的问题 
 
 问题的关键在于Clear方法会一个一个地删除每个Node, 
 
于是TreeView不断刷新,所以速度就.... 
 
代码修正一下: 
 
with MyTreeView.Items do 
 
<B>try</B> 
 
BeginUpdate; 
 
Clear; 
 
<B>finally</B> 
 
EndUpdate; 
 
<B>end;</B>



另外
1、你现在遇到的问题是大量删除,
如果是大量插入,也应该同样处理
2、ListView有同样问题,注意
其他Windows控件也有,但不很明显
比如Memo、RichEdit等等
总之,凡大量数据修改的情况下,
应该注意BeginUpdate和EndUpdate
3、<B>BeginUpdate和EndUpdate应该一一对应</B>,
因为Delphi实际上是用<B>计数器</B>来处理的,
如果忘了EndUpdate,
或者BeginUpdate比EndUpdate次数多,
可能导致控件不刷新了