TreeView的用法


 


一: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次数多, 

可能导致控件不刷新了 


elphi treeview添加节点  

 procedure TForm1.Button1Click(Sender: TObject); 


      var      
  MyTreeNode1, MyTreeNode2: TTreeNode;      
begin      
  with TreeView1.Items do      
  begin      
    Clear; { remove any existing nodes }      
    MyTreeNode1 := Add(nil, 'RootTreeNode1'); { Add a root node }      
    { Add a child node to the node just added }      
    AddChild(MyTreeNode1,'ChildNode1');     

          {Add another root node}      
    MyTreeNode2 := Add(MyTreeNode1, 'RootTreeNode2');      
    {Give MyTreeNode2 to a child }      
    AddChild(MyTreeNode2,'ChildNode2');     

          {Change MyTreeNode2 to ChildNode2 }      
    { and add a child node to it}      
    MyTreeNode2 := TreeView1.Items[3];      
    AddChild(MyTreeNode2,'ChildNode2a');     

          {Add another child to ChildNode2, after ChildNode2a }      
    Add(MyTreeNode2,'ChildNode2b');     

          {add another root node}      
    Add(MyTreeNode1, 'RootTreeNode3');      
  end;     

            


      一. 如何初始化一个TreeView?      
弄一个窗口,放上一个TreeView和一个Button,分别取名为TV1和Btn1。如果需要      
在每个节点前有个图,请在窗口上放上一个ImageList,取名为ImageList1,双击      
它,加入六个图标。还要记得记得将TV1的Images属性改为ImageList1噢。双击按      
钮Btn1,在里面填入以下代码,然后按F9运行,点击Btn1就可以看到效果了。      
procedure TForm1.Btn1Click(Sender: TObject);      
Const      
MyDocDir = 'C:/My Documents';      
PersonDir = '3hSoft';      
Var      
Var      
I : Word;      
SubNodeName : array [1..5] of ShortString;      
RootNode, SubNode : TTreeNode;      
P : PString;      
begin      
SubNodeName[1] := '便笺';      
SubNodeName[2] := '发件箱';      
SubNodeName[3] := '联系人';      
SubNodeName[4] := '任务';      
SubNodeName[5] := '日记';      
TV1.Items.Clear;      
TV1.Items.BeginUpdate;      
New(P);      
P^ := MyDocDir + '/' + PersonDir;      
RootNode := TV1.Items.AddObject(Nil, '个人文件夹', P);      
// 此 Node 的图标已对 Images 属性中取第 0 个了。      
For I := 1 to 5 do      
begin      
New(P);      
P^ := MyDocDir + '/' + PersonDir + '/' + SubNodeName[I];      
SubNode := TV1.Items.AddChildObject(RootNode, SubNodeName[I], P)      
;      
;      
// 如果不想使用图标的话请删除以下两行      
SubNode.ImageIndex := I;      
SubNode.SelectedIndex := I;      
end;      
TV1.Items.EndUpdate;      
end;      
二.在TreeView中如何设置选中结点      
var      
i:integer; {i为设置的选中结点的索引值}      
begin      
if i>treeview1.items.count then      
treeview1.items[i].selected:=true;      
或      
treeview1.selected:=treeview1.items[i];      
三。设置TreeView结点的图形      
1. 设置TreeView的images属性为已存在的images对象      
treeview1.images:=imagelist1;      
2. 在加入结点后执行:      
var      
anode:TTreeNode;      
begein      
anode:=Treeview1.add(nil,'item1');      
anode.imageindex:=0; {结点未选中时显示的图标}      
anode.selectedindex:=1; {结点选中时显示的图标}      
end      
3. 如果结点图形在改变后未发生变化,可以执行:      
treeview1.refresh;      
四。如何批量处理TreeView结点      
使用TreeView的items属性的BeginUpdate和EndUpdate方法,例:      
TreeView1.items.BeginUpdate;      
for i:=0 to TreeView1.items.count-1 do      
begin      
//将每个结点的文字改成为小写字母      
TreeView1.items[i].text:=lowercase(TreeView1.items[i].text);      
end;      
TreeView1.items.EndUpdate;     

      五。实现TreeView结点拖拽的实例      
下面的程序片段演示了如何实现拖拽treeview构件结点的例子      
{鼠标按下时执行的语句}      
procedure TForm1.Treeview1MouseDown(Sender: TObject;      
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);      
begin      
{判断左键按下并且鼠标点在一个结点上开始实现拖拽}      
if ( Button = mbLeft ) and      
( htOnItem in Treeview1.GetHitTestInfoAt( X, Y ) ) then      
begin      
Treeview1.BeginDrag( False );      
end;      
end;      
{鼠标拖动执行语句}      
procedure TForm1.Treeview1DragOver( Sender, Source: TObject;      
X, Y: Integer; State: TDragState; var Accept: Boolean);      
var      
Node : TTreeNode;      
begin      
if Source = Treeview1 then      
begin      
Node := Treeview1.GetNodeAt( X, Y ); {取当前结点}      
if Node <> nil then {当前结点不为空才能实现拖拽,accept:=true}      
Accept := true;      
end;      
end;      
{鼠标释放时执行的语句}      
procedure TForm1.Treeview1DragDrop( Sender, Source: TObject;      
X, Y : Integer );      
var      
TempNode : TTreeNode;      
AttachMode : TNodeAttachMode;      
begin      
if Treeview1.Selected = nil then      
Exit;      
AttachMode := naAddChild; {设置结点移动模式,设移动结点为子结点}      
{ 注意在这里存在一个bug,当移动结点时,如果目标结点没有子结点,}      
{ 则加入的新的子结点会失败,所以先在当前目标结点的下面 }      
{ 加入一个临时子结点,移动完毕后,再将临时结点删除 }      
Treeview1.Items.BeginUpdate;      
try      
TempNode := Treeview1.Items.AddChild( Treeview1.DropTarget,      
'Temp' );      
try      
{ 移动选中的结点到目标结点 }      
Treeview1.Selected.MoveTo( Treeview1.DropTarget, AttachMode );      
finally      
TempNode.Free; { 不要忘了释放临时结点 }      
end;      
finally      
Treeview1.Items.EndUpdate;      
end;      
end;

正在装载数据……