TreeView使用笔记
TreeView使用笔记
TreeView由节点构成,建树通过对TreeView.items属性进行操作。Items是一个TTreeNodes对象,这是一个TTreeNode集。
一、针对TTreeNodes,也就是 TreeView.Items,有这些属性:
1、count,节点个数。
2、item[index]? ,通过index得到节点。
二、针对TTreeNodes,也就是 TreeView.Items,常用的添加节点的操作有:
AddFirst添加第一个根节点。由此函数添加的节点总排在前面,除非后来又使用此函数添加了一个节点,则后添加的节点将排在前面。该函数返回新添加的节点。
AddChildFirst添加第一个子节点,要求有父节点作为其参数。返回新添加的节点。
AddChild添加一个子节点,要求有父节点作为其参数。返回新添加的节点。
Add添加一个兄弟节点,要求有兄弟节点作为其参数。返回新添加的节点。
三、针对TTreeNodes,也就是 TreeView.Items,常用的得到节点的操作有:
GetFirstNode() 得到根节点。
然后配合TTreeNode.GetNext(),就可以访问所有的节点。
四、建树举例:
var
? root_node,cur_node:TTreeNode;
begin
? root_node:=AddFirst(nil,根节点1);
? cur_node:=addChildfirst(root_node,nil,根节点1_child1);
? add(cur_node,根节点1_child2);
? root_node:=Add(nil,根节点2);
? AddChildFirst(root_node,根节点2_child1);?
end;
////////////////////////////////////////////////////////
TREEVIEW的简单使用
树形图(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操作,与标准的拖放操作使用方法一样
//////////////////////////
delphi中treeview控件如何高效的遍历一棵子树
只是查找指定节点??普通循环就行,比如下面这个是判断节点名是否匹配
var
i:integer;
begin
for i:=0 to TreeView1.Items.Count-1 do
if TreeView1.Items[i].Text='' then
break
//i就是你要查找的节点号
//treeview1.items[i]就是你要找的节点
end;
//////////////////////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
///////////////////////////
编程心得
1,在Delphi中,TreeView控件是一款很出色而且很常用的控件。
在使用过程中,了解到其TTreeNode对象的data属性存储相关数据很有用,一般情况下,我们先声明一个结构体以及其指针,例如:
type
PMyRc = ^TMyRc;
TMyRc = Record
id:string;
name:string;
age:integer;
end;
添加一个节点,显示信息为TMyRc的name,同时存储id,age。方法如下:
var
p:PMyRc;
i:integer;
begin
Randomize;
for i:= 0 to 9 do
begin
New(p);
p.id:=inttostr(random(100));
p.name:='name'+ inttostr(random(205));
p.age:=random(90);
// Caption := p.id+' '+P.name + ' '+inttostr(p.age);
TreeView1.Items.AddObject(nil,p.name,Tobject(p));
//dispose(p); 如果在这里释放指针,id,age并不能存在树中,而是在这里就被释放了。应该在释放树的事件里书写。
end;
end;
释放树的事件deletion, 即使是删除也会执行这些代码。所以不用担心内存泄漏。但是如果不书写以下代码,或者用相关的方式释放内存,必定会造成内存泄漏。
procedure TForm1.TreeView1Deletion(Sender: TObject; Node: TTreeNode);
begin
dispose(pmyrc(node.data));
end;
访问某个树枝中的age值:
Pmyrc(TreeView1.Selected.data)^.age
posted on 2005-03-29 12:41 长饮远醉 阅读(3981) 评论(2) 编辑 收藏 引用 网摘
问一个很简单的问题,Integer(treeview.Selected.Data)是什么意思?
data属性是一个指针,这句话的意思也就是把这个指针做为整数保存一下而已。
举个例子: Button1.Tag := Integer(Edit1);
这样可以把Edit1这个对象的指针放与Button1关联起来,在Button1Click事件里,你可以这么写:
prcedure TForm1.Button1Click(Sender: TObject);
var
EditObj : TEdit;
begin
EditObj := TEdit((Sender as TButton).Tag);
EditObj.Text := 'hello, world!';
end;
总之一句话,活用指针,你看的代码应该是一个喜欢用指针的人写的。
--------------------------------------------------------------------------------
当前被选中分枝保存的数据
(说的不太清楚,不知道你明不明白)
树型控件每个分枝有一个 DATA 属性 他是POINTER型的
可以存放数据,有点像TAG属性
这一句是把 DATA 里面的数据转换成INTEGER类型
--------------------------------------------------------------------------------
因为POINTER是个指针类型,所以INTEGER(treeview.Selected.Data)就是存放data的地址值.
--------------------------------------------------------------------------------
谢谢各位,明白不少了.
TMyData = class
end;
保存:
MyData := TMyData.Create;
...
TreeView.Items.AddObject('a node', MyData);
读出:
var
MyData: TMyData;
Mydata := TMyData(TreeView.Items[i].Data);
...
注意要释放这个对象,否则会丢失内存。
不知道是否已经解决了你的问题
Top
2 楼suzg(Eureka!)回复于 2001-03-07 14:42:00 得分 0 BaldZhang(BaldZhang)兄好快呀!
这个Data是个指针,不但可以指向类,还可以存数据(仅限于4字节),比如:
保存:
var
Num:Integer;
...
TreeView.Items.AddObject('a node', Pointer(Num));
读出:
var
Num:Integer;
....
Mydata := Integer(TreeView.Items[i].Data);
可以先建立一个对象,把你要保存的数据而又不想要显示的全部保存在对象中
然后使用items.addobject添加对象就可以了
例如
type node:=class
caption:string;
index:integer;
end;
var n:node;
begin
n:=node.create;
n.caption:='ad';
n.index:=1;
treeview.items.addoject(n);
end;
begin
showmessage(node(treelist.items.data[0]).caption);
showmessage(inttostr(node(treelist.items.data[0]).index));
end;
如何?
////
while not ADOTable_NoteBook.Eof do
begin
FindListBox.Items.AddObject(ADOTable_NoteBook.FieldByname('recTitle').AsString, pointer(ADOTable_NoteBook.FieldByname('recSerial').asinteger));
//这一句是你要的
ADOTable_NoteBook.Next ;
end;
///////
这样
tpye
Pyourtype=^yourtype;
yourtype=record
yy:word;
mm:word;
dd:word;
end;
var item:Ttreenode;
n:Pyourtype;
begin
new(n);
n.yy:=2002;n.mm=9;n.dd:=6;
item:=treeview.add;
item.caption:='根';
item.addchildobject('shuju',n);
end;
begin
showmessage('今年是'+inttostr(Pyourtype(treeview1.selected.date)^.yy));
end;
为了不浪费存储空间,直接把整数存储在data中,如果其他数据类型不行哦,
存储:
TreeView1.Items.Item[0].Data:=pointer(4);
取值:
i:=inttostr(integer(TreeView1.Items.Item[0].Data));
/////////////////////
Delphi中使用ListView和TreeView的Item中的Data可能被忽略的内存泄漏2007/03/20 09:53 P.M.
Delphi中大家在使用 ListView和TreeView时,一般都会使用到Item的Data属性来保存大家自己的内部数据,这个Data的声明如下:
property Data: Pointer;
大家可以看到它就是一个指针,使用上一般类似如下代码(以ListView为)
添加时
PViewItemState = ^TViewItemState;
TViewItemState = record
ViewItemId: integer;
end;
var
nLoop: integer;
li: TListItem;
pp: PViewItemState;
begin
for nLoop := 0 to 10 do
begin
li := ListView1.Items.Add;
li.Caption := IntToStr(nLoop);
new(pp);
pp^.ViewItemId := nLoop;
li.Data := pp;
end;
end;
删除相应的项时多数采用
ListView1.DeleteSelected; 或
ListView1.Clear;
就结束了操作。
但是这里存在非常大的危险,就是我们的自己分配的Data内容有没有释放,Delphi文档中也没有关于这个问题的说明,所以我做了一个测试,发现Delphi是不自动释放这些数据的,这些未释放的数据在一个包含较多修改的ListView或者TreeView中将非常危险,如果是长期运行的系统将更危险,Delphi文档中也没有提示这些数据需要释放。
其实这个问题容易被大家忽略,解决办法还是有的,而且也不难,这里就要使用到ListView或者TreeView的OnDeletion事件,Delphi中关于OnDeletion的说明如下:
Occurs when an item in the list view is about to be deleted.
Delphi syntax:
property OnDeletion: TLVDeletedEvent;
C++ syntax:
__property TLVDeletedEvent OnDeletion = {read=FOnDeletion, write=FOnDeletion};
Description
Write an OnDeletion event handler to respond when an item in the list is about to be deleted. The Item parameter is the TListItem object from the Items property that is about to be deleted.
也就是说当需要删除项目时会触发这个事件,在VCL Source 中也可以看到调用过程,其实解决方法就是在这个事件中加入一个语句就可以了,并且是不可以缺少的语句,代码如下:
procedure TForm1.ListView1Deletion(Sender: TObject; Item: TListItem);
begin
Dispose(Item.Data);
end;
这样就可以安全的释放掉Data的内存了。