delphi中treeview的使用
- 格式:docx
- 大小:33.96 KB
- 文档页数:20
Delphi中为TreeView添加单选和复选框 打开电脑,进⼊Windows操作系统,在资源管理器的左边栏中清楚地显⽰了系统管理的所有磁盘的信息以及各个磁盘所容纳的⽂件与⽂件夹(如图⼀)。
这种常见的显⽰⽅式是由⼀个根节点和若⼲个⼦节点构成的,这被称为“树形结构”。
这种树形结构的⽤途⾮常⼴泛,在很多常⽤软件中都出现过它的⾝影。
Windows中将这种结构封装为“树形控件”,即TreeView控件,它与ListView、Button等⼀样都属于系统⾃带的通⽤公共控件。
在Delphi中,TreeView也被封装成了VCL组件,它的位置在“Win32组件”⾯板上,是我们最常⽤的⼏个组件之⼀。
Delphi⾃带的TreeView组件可以显⽰树形结构,也可以为每个节点指定不同的图标来区分各⾃的功能。
但在平时的使⽤中,我们发现它并不能嵌⼊CheckBox或者是RadioButton组件,这样⽤户就不能直观地选择某⼀部分节点或某个节点。
如何来解决这个问题呢?我们思考之后发现,有两种思路可以完成前⾯所述的任务。
⼀种是在TreeView组件的基础上继承的它的功能,并添加所要的功能(使TreeView能嵌⼊CheckBox或者是RadioButton组件)即重写⼀个组件。
另⼀种是利⽤⽤户的错觉,将CheckBox或者是RadioButton所能实现的外观⽤两种状态的图⽚(⼀种是选中状态另⼀种是未选中状态)来交替显⽰,⾛迂回路线来完成任务。
我们来分析⼀下这两种⽅法的优缺点:第⼀种⽅法要重写⼀个组件,显然难度较⼤,所⽤时间较长;第⼆种⽅法,利⽤TreeView组件本⾝就具备的显⽰图标功能,简便易⾏,所⽤时间短,能够完成需求。
⽐较之后,我们选择作⽤第⼆种⽅法,先来看⼀下完成之后的效果(如图⼆),应该说是达到了⽬的,现在我们来细述⼀下完成的过程: ⾸先,我们在Win32⾯板上选择ImageList组件,设置它的StateImages属性,包括两种状态的图标,⼀种是选中状态,另⼀种是未先中状态。
DelPhi Treeview 操作实例onclick节点treeview1.Selected.Level2011-08-31 15:58怎么改变Treeview中的图标? OnClick事件Click获取Node.text 批量处理及实现TreeView结点拖拽的实例//这个过程根据你的要求选择图标procedure TForm1.TreeView1GetImageIndex(Sender: TObject; Node: TTreeNode);beginif Node.HasChildren thenif Node.Expanded thenNode.ImageIndex := 3 //节点有子节点时打开的图标elseNode.ImageIndex := 0 //节点有子节点时收起来的图标else Node.ImageIndex := 1; //节点没有子节点时图标end;//这个过程显示选择的图标procedure TForm1.TreeView1GetSelectedIndex(Sender: TObject; Node: TTreeNode);beginNode.SelectedIndex := Node.ImageIndex; //节点选择后使用的图标end;——————————————————————————————————-//treeview的单击事件procedure TForm1.TreeView1Click(Sender: TObject);begin//如果选中节点的等级(level)为0(根节点等级为0,根节点的子节点等级为1,依次类推)并且其序号(index)为0(同等级下的的节点按从上到下数第一个为0,第二个为1,以此类推)if(treeview1.Selected.Level = 0)and(treeview1.Selected.Index = 0) thenbegin//这里写点中了第一个根节点后要做的事form1.Color := clred;endelseif (treeview1.Selected.Level = 1)and(treeview1.Selected.Index=1) thenbegin//这里写点中了第三个根节点的第2个子节点后要做的事form1.Color := clblue;end;end;//如果你想点节点前的“+”号也有同样的效果,那么就应该在Expanding事件里写判断处理程序。
一:TreeView.Items[0].Expanded:=True;//展开第一个节点二:TreeView.Items[0].Item[0].Selected:=True;//移动到第一个节点的第一个子节点找当前节点的下一个节点,按序号找如下:if treeview1.Selected.GetNext<>nil thentreeview1.Selected.GetNext.Selected:=true;TreeView1.SetFocus;找当前节点的下一个同层兄弟如下:if treeview1.Selected.getNextSibling<>nil thentreeview1.Selected.getNextSibling.Selected:=true;TreeView1.SetFocus;TreeView.Selected.getPrevSibling//当前选中节点的上一个兄弟节点TreeView.Selected.Parent//当前选中节点的父节点getfirstchild是跳到该节点子结点中的第一个getlastchild是跳到该节点子结点中的最后一个如果你是想跳到同层兄弟结点的第一个if treeview1.selected.parent<>nil thentreeview1.selected.parent.getfirstchild.selected:=trueelsetreeview1.items.item[0].selected:=true;如果你是想跳到同层兄弟结点的最后一个if treeview1.selected.parent<>nil thentreeview1.selected.parent.getlastchild.selected:=trueelsetreeview1.Items.Item[treeview1.Items.Count-1].Selected:=true;TreeView的使用方法基本信息:TreeView是一个显示树型结构的控件,每一个节点都是一个新类,使用具有代表性每个节点都有四个值:TEXT:显示文字Image Index:显示图形序号Selected Index:State Index:(1)建立目录项(本例中使用的TREEVIEW名称为:TvwTips)增加根目录下的节点:(节点)varCatNode:TTreeNode;//先建立一个TREEVIEW使用的子对象beginTvwTips.SetFocus;//将焦点置到这个TREEVIEW控件上{在根标题下建立一个新的子标题}CatNode:=TvwTips.Items.AddChild(TvwTips.Items.GetFirstNode,'New Category');CatNode.ImageIndex:=1;CatNode.SelectedIndex:=2;CatNode.EditText;{允许用户改变这个标题}end;增加下一级目录(内容):varParentNode,TipNode:TTreeNode;//先建立TREEVIEW使用的子对象VersionNum:Integer;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,'NewSubject',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的第一个节点,函数类型为:TTreeNodeTvwTips.Items.Count返回当前TreeView的全部节点数,整数TvwTips.Selected.Level返回当前选中节点的在目录树中的级别,根目录为0TvwTips.Selected.Parent返回当前选中节点上级节点,函数类型为:TTreeNode三、下面这段程序是用TREEVIEW连数据库及一些操作:unit bmzd;usesWindows,Messages,SysUtils,Classes,Graphics,Controls,Forms,Dialogs, StdCtrls,ComCtrls,Db,DBTables,ImgList,Buttons,ExtCtrls,Grids, DBGrids;typeTfrmbmzd=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;varfrmbmzd:Tfrmbmzd;ii:integer;tv:ttreenode;constSCodeFormat='222222';//科目代码结构SFirstNodeTxt='部门分类';implementationuses dm;{$R*.DFM}function tfrmbmzd.LoadCode(crTbl:TDBDataSet):Integer; var NowID,sName,ShowTxt:String;i,Level:Integer;MyNode:array[0..6]of TTreeNode;//保存各级节点,最长支持6级(重点)beginScreen.Cursor:=crHourGlass;Level:=0;With frmdm.tabbm dobegintryif 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 dobeginNowID:=Trim(FieldByName('bumeng_id').AsString); ShowTxt:=FieldByName('bumeng_name').AsString; Level:=GetLevel(SCodeFormat,NowID);//返回代码的级数//以下是增加子项//以下用上一级节点为父节点添加子节点if Level>0then//确保代码符合标准beginMyNode[Level]:=tvwCode.Items.AddChild(MyNode[Level-1],NowID+''+ShowTxt);MyNode[Level].ImageIndex:=1;MyNode[Level].SelectedIndex:=2;end;//以上是增加子项Next;end;finallyClose;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;beginLevel:=-1;//如果代码不符合标准,则返回-1iLen:=0;if(sFormat<>'')and(sCode<>'')thenfor i:=1to Length(sFormat)doiLen:=iLen+StrToInt(sFormat[i]);if Length(sCode)=iLen thenbeginLevel:=i;Break;end;end;Result:=Level;end;procedure Tfrmbmzd.FormShow(Sender:TObject);beginif 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); beginAction:=caFree;end;procedure Tfrmbmzd.cmd_newClick(Sender:TObject);tvwcode.SetFocus;if tvwcode.selected.AbsoluteIndex<>0thenbegincmd_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 thenbeginif tvwcode.Selected.GetLastChild.index+1>9thenedit2.text:=inttostr(tvwcode.Selected.GetLastChild.index+1) elseedit2.text:='0'+inttostr(tvwcode.Selected.GetLastChild.index+1); edit3.text:='新建部门';edit2.Enabled:=true;edit3.Enabled:=true;endelsebeginedit2.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);varI:integer;seno,setext:string;beginif tvwcode.Selected.HasChildren=true thenbeginapplication.messagebox('该部门包含下级,不能删除','提示',MB_OKCANCEL+mb_iconquestion);endelsebeginif application.messagebox('你确实要删除当前部门吗','提示',MB_OKCANCEL+mb_iconquestion)=IDOKbeginsetext:=tvwcode.selected.text;i:=0;while setext[i]<>''dobeginI:=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 thenbeginfrmdm.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); beginif key in['0'..'9',Chr(vk_Back)]thenbeginkey:=#0;application.messagebox('','',mb_ok);end;end;procedure wcodeChange(Sender:TObject;Node:TTreeNode); vari,lev:integer;strr,seno,setext:string;beginif cmd_new.Enabled=true thenbeginif tvwcode.selected.AbsoluteIndex<>0thenbegincmd_delete.Enabled:=true;cmd_update.Enabled:=true;cmd_save.Enabled:=true;setext:=tvwcode.selected.text;i:=0;while setext[i]<>''dobeginI:=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 of2: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);endelsebeginedit1.text:='';edit2.text:='';edit3.text:='部门分类';cmd_delete.Enabled:=false;cmd_update.Enabled:=false;end;end;end;procedure Tfrmbmzd.cmd_updateClick(Sender:TObject);vari:integer;beginfor i:=0to ComponentCount-1dobeginif(Components[I]is tedit)then(Components[I]as tedit).enabled:=false;end;for i:=0to ComponentCount-1dobeginif(Components[I]is tbitbtn)then(Components[I]as tbitbtn).enabled:=true;end;if tvwcode.Selected.AbsoluteIndex<>0thenbeginif 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;tryfrmdm.tabbm.Post;//表的保存excepton edbengineerror dobeginedit2.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);begincmd_new.Enabled:=false;cmd_delete.Enabled:=false;edit2.enabled:=true;edit3.Enabled:=true;end;procedure wcodeClick(Sender:TObject);vari:integer;beginif cmd_new.Enabled=false thenbeginapplication.MessageBox('当前是修改状态,请单击保存按钮','提示',mb_ok); tv.Selected:=true;end;if tvwcode.selected.AbsoluteIndex=0thenbeginfor i:=0to ComponentCount-1dobeginif(Components[I]is tedit)then(Components[I]as tedit).enabled:=false;end;for i:=0to ComponentCount-1dobeginif(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控件。
DELPHI中利用TreeView控件建立目录树2000-06-26 00:00:00·-·中国计算机报社p>Rainbow的话:关于TreeView的使用,还可以参看:联合使用TreeView 组件TreeView是一个显示树型结构的控件,通过它能够方便地管理和显示具有层次结构的信息,是Windows应用程序的基本控件之一。
DELPHI虽然具有比较强大的文件管理功能,提供了多个用于文件管理的标准控件,如DriveComboBox、DirectoryListBox、FileListBox等,通过设置它们的属性,使其建立起联系,甚至不用编写一行程序,我们就可以实现在不同的目录之间进行切换,然而这样的目录切换只适用于进行文件的查找定位,而不能方便地进行目录的浏览,例如我们要从c:\windows目录转到c:\program files目录,就必须返回到根目录才能进行切换,而不能象Windows资源管理器那样任意地在不同的目录之间进行浏览与切换。
要实现在不同目录之间任意切换和浏览,还是需要使用TreeView控件,以下程序就利用DELPHI的TreeView控件来建立目录树。
在该程序中采用的各部件以及界面设计如下图所示:各部件的主要属性设置如下:部件属性属性值form namecaptionform1 ‘目录浏览’drivecommbobox name visible drivecommbobox1 falsefilelistbox name visible filetype filelistbox1 false fddirectoryimagelist name imagelist1treeview name images该程序利用DriveCommboBox控件来获得系统具有的驱动器,并以此作为目录树的最上层,利用FileListBox控件,通过设置其Filetype属性为fdDirectory,可以获得所需的子目录,在TreeView控件的OnExpanding事件中将得到的子目录加到该控件的某一节点下。
Delphi中⽤Xml配置⽂档⽣成Treeview⽤递归⽅法,使⽤ xml ⽂档⽣成 Treeview 树形视图。
由于是动态⽣成,所以可以通过修改 xml 的逻辑来定制 Treeview 的结构,从⽽实现了 xml 对 Treeview 的动态配置,⽽不⽤修改代码。
xml ⽂件如下:<?xml version="1.0" encoding="gb2312"?><root topic="频道列表" catalog="none"><channel topic="操作系统" catalog="none"><channel topic="Windows频道" catalog="windows" /><channel topic="DOS频道" catalog="dos" /><channel topic="Linux" catalog="linux" /></channel><channel topic="菜鸟专区" catalog="cainiaozhuanqu" /><channel topic="应⽤软件" catalog="app" /><channel topic="安全专区" catalog="safe" /><channel topic="代码实验室" catalog="lab" /><BBS topic="电脑学习社区" catalog="none"><subBBS topic="⼦社区-1" catalog="sub1" /><subBBS topic="⼦社区-2" catalog="sub2" /></BBS></root>程序代码如下:unit tree_xml;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls,Forms, Dialogs, ComCtrls, StdCtrls, XMLDoc, XMLIntf;typeTForm1 = class(TForm)TreeView1: TTreeView;Memo1: TMemo;Button1: TButton;procedure TreeView1MouseDown(Sender: TObject; Button: TMouseButton;Shift: TShiftState; X, Y: Integer);procedure Button1Click(Sender: TObject);privatefunction CreateTreeview(XmlNode: IXMLNode; TreeNode: TTreeNode):TTreeNode;{ Private declarations }public{ Public declarations }end;typepRec = ^TData;TData = recordsCatalog: string;sReserved: Stringend;varForm1: TForm1;implementation{$R *.dfm}function TForm1.CreateTreeview(XmlNode: IXMLNode; TreeNode: TTreeNode): TTreeNode;vari: integer;ParentTreeNode, CurrentTreeNode: TTreeNode;pData: pRec;beginNew(pData);pData^.sCatalog := XmlNode.AttributeNodes['catalog'].NodeValue;CurrentTreeNode := TreeView1.Items.AddChildObject(TreeNode,XmlNode.AttributeNodes['topic'].NodeValue, pData); //pointer(...)if XmlNode.HasChildNodes thenbeginParentTreeNode := CurrentTreeNode;for i:=0 to XmlNode.ChildNodes.Count-1 dobeginCreateTreeview(XmlNode.ChildNodes[i], ParentTreeNode);end;end;result := CurrentTreeNode;end;{------------------------------------------------------------------}procedure TForm1.TreeView1MouseDown(Sender: TObject; Button: TMouseButton;Shift: TShiftState; X, Y: Integer);var pData: pRec;beginpData := Treeview1.Selected.Data;Memo1.Lines.Add(pData^.sCatalog);end;procedure TForm1.Button1Click(Sender: TObject);varoXml: TXMLDocument;beginoXml := TXMLDocument.Create(self);oXml.FileName := '_Treeview.xml';oXml.Active:=true;CreateTreeview(oXml.ChildNodes.FindNode('root'), Treeview1.Items.GetFirstNode);Treeview1.FullExpand; //节点全部展开oXml.Free;end;end.注意程序中 Treeview 的 TreeView1.Items.AddChildObject ⽅法,其最后⼀个参数⽤来保存该节点的相关数据,是⼀个指针类型的数据,使⽤时要格外⼩⼼。
delphi中treeview的使用delphi中Treeview的使用介绍每一个节点下子节点形成这一节点的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属性表明一个节点是否被选中,同样只有一个节点会被选中。
DropT arget属性表明节点在拖动操作中是源还是目标。
.1.添加、删除、修改节点:静态的方法可以在设计时通过Items的编辑器设置各节点的内容。
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(),就可以访问所有的节点。
四、建树举例:varroot_node,cur_node:TTreeNode;beginroot_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;五、事件触发:当从一个节点跳到另一个节点,会触发TTreeView.OnChange事件。
该事件中,将传递node,即当前被选中的节点。
delphitreeview节点移动函数//TreeView节点移动函数,支撑同级移动跟任意移动。
up代表移动方向,true上移false下移;//同级移动的时候须要传进选中节点的level,免意挪动level=-1 procedureUpDownNode(node:TTreeNode;up:boolean;level:integer);var TargetNode: TTreeNode;beginif (level<>-1) then //同级间移动beginif (node <>nil)then //检查是否有选中节点如果有则做上移操作beginif (up) then //上移beginif (node.GetPrev <> nil) thenbeginTargetNode := node.GetPrev;while TargetNode.Level <> level dobeginif TargetNode.GetPrev=nil thenbreakelseTargetNode := TargetNode.GetPrev;end;if (TargetNode<>nil) thenbeginif (TargetNode.Level=level) thenbeginif (node.getPrevSibling <> nil) then //检查是否有同级上一节点beginif (node.getPrevSibling <> nil) thennode.MoveTo(TargetNode,naInsert)elsenode.MoveTo(TargetNode,naAddFirst);end elsebeginnode.MoveTo(TargetNode,naAdd);end;end;end;end;end else //下移beginif (node.GetNext <> nil) thenbeginTargetNode := node.getNext;while TargetNode.Level <> level dobeginif TargetNode.GetNext=nil thenbreakelseTargetNode := TargetNode.getNext;end;if (TargetNode<>nil) thenbeginif (TargetNode.Level=level) thenbeginif (node.getNextSibling <> nil) then //检讨是否有同级上一节beginif (TargetNode.getNextSibling <> nil) thennode.MoveTo(TargetNode.getNextSibling,naInsert)elsenode.MoveTo(TargetNode,naAdd);end elsebeginnode.MoveTo(TargetNode,naInsert);end;end;end;end;end;end;end else //容许跨级移动beginif (node <> nil)then //检讨是否有选中节点假如有则做上移操作beginif (up) then //上移beginif (node.GetPrev <> nil) thenbeginTargetNode := node.GetPrev;if (TargetNode<>nil) thenbeginif (node.GetPrev <> nil) then //检查是否有同级上一节点如果有做上移操作beginif (node.GetPrev <> nil) thennode.MoveTo(TargetNode,naInsert)elsenode.MoveTo(TargetNode,naAddFirst);end elsebeginnode.MoveTo(TargetNode,naAdd);end;end;end;end else //下移beginif (node.GetNext <> nil) thenbeginTargetNode := node.GetNext;while TargetNode.Parent = node dobeginif TargetNode.GetNext=nil thenbreakelseTargetNode := TargetNode.getNext;end;if (TargetNode<>nil) thenbeginif (node.GetNext <> nil) then //检讨是否有共级上一节点假如有干上移操息beginif (TargetNode.getNext <> nil) thennode.MoveTo(TargetNode.getNext,naInsert)elsenode.MoveTo(TargetNode,naAdd);end elsebeginnode.MoveTo(TargetNode,naAdd); end;end;end;end;end;end;end;。
delphi中TreeView使⽤常见问题编程⼼得1,在Delphi中,TreeView控件是⼀款很出⾊⽽且很常⽤的控件。
在使⽤过程中,了解到其TTreeNode对象的data属性存储相关数据很有⽤,⼀般情况下,我们先声明⼀个结构体以及其指针,例如:typePMyRc = ^TMyRc;TMyRc = Recordid:string;name:string;age:integer;end;添加⼀个节点,显⽰信息为TMyRc的name,同时存储id,age。
⽅法如下:varp:PMyRc;i:integer;beginRandomize;for i:= 0 to 9 dobeginNew(p);p.id:=inttostr(random(100));:='name'+ inttostr(random(205));p.age:=random(90);// Caption := p.id+' '+ + ' '+inttostr(p.age);TreeView1.Items.AddObject(nil,,Tobject(p));//dispose(p); 如果在这⾥释放指针,id,age并不能存在树中,⽽是在这⾥就被释放了。
应该在释放树的事件⾥书写。
end;end;释放树的事件deletion,即使是删除也会执⾏这些代码。
所以不⽤担⼼内存泄漏。
但是如果不书写以下代码,或者⽤相关的⽅式释放内存,必定会造成内存泄漏。
procedure TForm1.TreeView1Deletion(Sender: TObject; Node: TTreeNode);begindispose(pmyrc(node.data));end;访问某个树枝中的age值:Pmyrc(TreeView1.Selected.data)^.age。
TreeView 的用法开始(挺全的)//************* TreeView 的用法开始******************//一:TreeView.Items[0].Expanded := True; // 展开第一个节点二:TreeView.Items[0].Item[0].Selected := True; // 移动到第一个节点的第一个子节点找当前节点的下一个节点,按序号找如下:if treeview1.Selected.GetNext<>nil thentreeview1.Selected.GetNext.Selected:=true;TreeView1.SetFocus;找当前节点的下一个同层兄弟如下:if treeview1.Selected.getNextSibling<>nil thentreeview1.Selected.getNextSibling.Selected:=true;TreeView1.SetFocus;TreeView.Selected.getPrevSibling //当前选中节点的上一个兄弟节点TreeView.Selected.Parent // 当前选中节点的父节点getfirstchild是跳到该节点子结点中的第一个getlastchild是跳到该节点子结点中的最后一个如果你是想跳到同层兄弟结点的第一个if treeview1.selected.parent<>nil thentreeview1.selected.parent.getfirstchild.selected:=trueelsetreeview1.items.item[0].selected:=true;如果你是想跳到同层兄弟结点的最后一个if treeview1.selected.parent<>nil thentreeview1.selected.parent.getlastchild.selected:=trueelsetreeview1.Items.Item[treeview1.Items.Count-1].Selected:=true;TreeView的使用方法基本信息:TreeView 是一个显示树型结构的控件,每一个节点都是一个新类,使用具有代表性每个节点都有四个值:TEXT:显示文字 Image Index:显示图形序号Selected Index:State Index:(1)建立目录项(本例中使用的TREEVIEW名称为:TvwTips)增加根目录下的节点:(节点)varCatNode : TTreeNode; //先建立一个TREEVIEW使用的子对象beginTvwTips.SetFocus; //将焦点置到这个TREEVIEW控件上{ 在根标题下建立一个新的子标题 }CatNode := TvwTips.Items.AddChild(TvwTips.Items.GetFirstNode,'New Category' );CatNode.ImageIndex := 1;CatNode.SelectedIndex := 2;CatNode.EditText; { 允许用户改变这个标题 }end; 增加下一级目录(内容):varParentNode, TipNode : TTreeNode; //先建立TREEVIEW使用的子对象VersionNum : Integer;beginTvwTips.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的第一个节点,函数类型为:TTreeNodeTvwTips.Items.Count 返回当前TreeView的全部节点数,整数TvwTips.Selected.Level 返回当前选中节点的在目录树中的级别,根目录为0TvwTips.Selected.Parent 返回当前选中节点上级节点,函数类型为:TTreeNode三、下面这段程序是用TREEVIEW连数据库及一些操作:unit bmzd;interfaceusesWindows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls, Db, DBTables, ImgList, Buttons, ExtCtrls, Grids,DBGrids;typeTfrmbmzd = 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: TLabelLabel5: 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;varfrmbmzd: Tfrmbmzd;ii:integer;tv:ttreenode;constSCodeFormat = '222222'; //科目代码结构SFirstNodeTxt = '部门分类';implementationuses dm;{$R *.DFM}function tfrmbmzd.LoadCode(crTbl:TDBDataSet):Integer;var NowID,sName,ShowTxt:String;i,Level:Integer;MyNode:array[0..6]of TTreeNode;//保存各级节点,最长支持6级(重点)beginScreen.Cursor:=crHourGlass;Level:=0;With frmdm.tabbm dobegintryif 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 dobeginNowID:=Trim(FieldByName('bumeng_id').AsString); ShowTxt:=FieldByName('bumeng_name').AsString; Level:=GetLevel(SCodeFormat,NowID);//返回代码的级数//以下是增加子项//以下用上一级节点为父节点添加子节点if Level>0 then//确保代码符合标准beginMyNode[Level]:=tvwCode.Items.AddChild (MyNode[Level-1],NowID+' '+ShowTxt);MyNode[Level].ImageIndex:=1;MyNode[Level].SelectedIndex:=2;end; //以上是增加子项Next;end;finallyClose;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;beginLevel:=-1;//如果代码不符合标准,则返回-1iLen:=0;if (sFormat<>'')and(sCode<>'')thenfor i:=1 to Length(sFormat) dobeginiLen:=iLen+StrToInt(sFormat[i]);if Length(sCode)=iLen thenbeginLevel:=i;Break;end;end;Result:=Level;end;procedure Tfrmbmzd.FormShow(Sender: TObject);beginif 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); beginAction := caFree;end;procedure Tfrmbmzd.cmd_newClick(Sender: TObject);begintvwcode.SetFocus ;if tvwcode.selected.AbsoluteIndex<>0 thenbegincmd_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 thenbeginif tvwcode.Selected.GetLastChild.index+1>9 thenedit2.text:=inttostr(tvwcode.Selected.GetLastChild.index+1)elseedit2.text:='0'+inttostr(tvwcode.Selected.GetLastChild.index+1);edit3.text:='新建部门';edit2.Enabled:=true;edit3.Enabled:=true;endelsebeginedit2.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); varI:integer;seno,setext:string;beginif tvwcode.Selected.HasChildren=true thenbeginapplication.messagebox('该部门包含下级,不能删除','提示',MB_OKCANCEL+mb_iconquestion ) ;endelsebeginif application.messagebox('你确实要删除当前部门吗','提示',MB_OKCANCEL+mb_iconquestion )=IDOK thenbeginsetext:=tvwcode.selected.text;i:=0;while setext[i] <> ' ' dobeginI := 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 thenbeginfrmdm.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); beginif key in ['0'..'9',Chr(vk_Back)] thenelsebeginkey:=#0;application.messagebox('','',mb_ok);end;end;procedure wcodeChange(Sender: TObject; Node: TTreeNode);vari,lev:integer ;strr,seno,setext:string;beginif cmd_new.Enabled =true thenbeginif tvwcode.selected.AbsoluteIndex<>0 thenbegincmd_delete.Enabled:=true;cmd_update.Enabled:=true;cmd_save.Enabled :=true;setext:=tvwcode.selected.text;i:=0;while setext[i] <> ' ' dobeginI := 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 of2: 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 );endbeginedit1.text :='';edit2.text :='';edit3.text :='部门分类';cmd_delete.Enabled :=false;cmd_update.Enabled :=false;end;end;end;procedure Tfrmbmzd.cmd_updateClick(Sender: TObject); vari:integer;beginfor i:=0 to ComponentCount-1 dobeginif (Components[I] is tedit ) then(Components[I] as tedit).enabled:=false;end;for i:=0 to ComponentCount-1 dobeginif (Components[I] is tbitbtn ) then(Components[I] as tbitbtn).enabled:=true;end;if tvwcode.Selected.AbsoluteIndex<>0 thenbeginif 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;tryfrmdm.tabbm.Post;//表的保存excepton edbengineerror doedit2.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);begincmd_new.Enabled :=false;cmd_delete.Enabled :=false;edit2.enabled:=true;edit3.Enabled :=true;end;procedure wcodeClick(Sender: TObject);vari:integer;beginif cmd_new.Enabled =false thenbeginapplication.MessageBox('当前是修改状态,请单击保存按钮','提示',mb_ok);tv.Selected :=true;end;if tvwcode.selected.AbsoluteIndex=0 thenbeginfor i:=0 to ComponentCount-1 dobeginif (Components[I] is tedit ) then(Components[I] as tedit).enabled:=false;end;for i:=0 to ComponentCount-1 dobeginif (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控件。
VirtualTreeview使用说明很好用的一个列表控件,可以用来代替Delphi自带的ListView和TreeView,而且也一直在更新,目前已经支持最新的XE2官方网站:SVN地址:/svn/trunk基本的使用方法就不多说了,可以看看Demo,或者百度一下还是有些教程的。
我这里只记录一些属性方法等,方便查阅【属性】EditDelay = 单元格编辑响应时间HintAnimation = Hint动画效果HintMode = Hint显示方式LineMode = 网格线条模式LineStyle = 网格线条样式Header > AutoSizeIndex = 自适应宽度的列索引Header > Options > hoAutoResize = 列自适应宽度开关Header > Options > hoColumnResize = 是否可以自由调整列宽Header > Options > hoDblClickResize = 双击分界线自动改变列度Header > Options > hoDrag = 是否支持拖拽移动Header > Options > hoHotTrack = 高亮显示当前列Header > Options > hoHeightResize = 是否可以自由调整列高TreeOptions > AutoOptions > toAutoExpand = 单击展开节点并收起其他节点TreeOptions > AutoOptions > toAutoTristateTracking = 三态复选框自适应选择,即子节点被选择后父节点Check状态改变TreeOptions > MiscOptions > toCheckSupport = 是否显示复选框。
还需要设置节点的CheckType属性TreeOptions > MiscOptions > toEditable = 是否允许单击编辑单元格TreeOptions > MiscOptions > toFullRepaintOnResize = 控件大小改变时刷新显示数据TreeOptions > MiscOptions > toToggleOnDblClick = 双击展开节点TreeOptions > PaintOptions > toHideSelection = 隐藏选择焦点TreeOptions > PaintOptions > toHotTrack = 当前行是否显示下划线TreeOptions > PaintOptions > toShowDropmark = 拖拽时是否显示插入标记TreeOptions > PaintOptions > toShowRoot = 是否显示父节点展开按钮TreeOptions > PaintOptions > toShowHorzGridLines = 水平网格线开关TreeOptions > PaintOptions > toShowTreeLines = 父节点与子节点的连接线TreeOptions > PaintOptions > toShowVertGridLines = 垂直网格线开关TreeOptions > PaintOptions > toThemeAware = 应用系统主题TreeOptions > PaintOptions > toAlwaysHideSelection = 总是隐藏选择TreeOptions > PaintOptions > toChildrenAbove = 父节点处于子节点下方TreeOptions > SelectionOptions > toDisableDrawSelection = 框选开关TreeOptions > SelectionOptions > toExtendedFocus = 是否允许Cloumn>0的单元格有焦点(有焦点的时候才能编辑)TreeOptions > SelectionOptions > toFullRowSelect = 整行选择TreeOptions > SelectionOptions > toMultiSelect = 是否可以多选TreeOptions > SelectionOptions > toRightClickSelect = 右键是否可以选择TreeOptions > SelectionOptions > toSimpleDrawSelection = 框选时只要该行处于框内即可被选择TreeOptions > StringOptions > toShowStaticText = 是否显示静态文本(在节点正文后面显示的字符,静态文本不能编辑)【方法】TopNode = 设置列表顶部的节点,可以用来定位节点行ScrollIntoView = 设置滚动条位置,可以用来定位节点行【事件】OnChange = 焦点改变时OnCreateEditor = 设置某单元格的编辑框样式,比如TEdit,TComboBox等等。
[编程]DELPHI--TreeView与数据库的使用//写一个过程procedure Tf_Serch.DrawTree;vari: Integer;Nodeo: TTreeNode;begin//打开一个表with dm.qTempQ dobeginClose;SQL.Clear;SQL.Add('select * from t_class order by 编号');Open;end;//打开第二个表with dm.qKid dobeginClose;SQL.Clear;SQL.Add('select * from t_kid order by 班级编号');Open;end;//清空列表RzTreeView1.Items.Clear;//如果第一个表有数据if not dm.qTempQ.Eof thenbegin//设置列表自动打开RzTreeView1.AutoExpand := true;//设置列表为只读RzTreeView1.ReadOnly := true;//增加一个节点,来源是第一个表的合计数和第二个表的合计数 Nodeo := RzTreeView1.Items.AddFirst(nil, '班级数['+ IntToStr(dm.qTempQ.RecordCount) + '个' + IntToStr(dm.qKid.RecordCount) + '人]'); //以第一个表的记录个数进行循环增加子节点for i := 0 to dm.qTempQ.RecordCount - 1 dobegin//打开第三个表,与第二个表相同with dm.qTemp1 dobeginClose;SQL.Clear;SQL.Add('select * from t_kid');Open;//不同的是,这个表过滤数据Filtered := false;Filter := '班级编号 = ' + QuotedStr(dm.qTempQ.FieldByName('编号').AsString);Filtered := true;end;//增加子节点,来源是第一个表某字段的记录和第三个表的合计数RzTreeView1.Items.AddChild(Nodeo, '[' + IntToStr(dm.qTemp1.RecordCount) + '人]'+ dm.qTempQ.FieldByName('名称').Asstring);//第一个表的下一条dm.qTempQ.Next;end;end;if RzTreeView1.Enabled then RzTreeView1.SetFocus;end;//CLICK事件procedure Tf_Serch.RzTreeView1Click(Sender: TObject);varStrPos: string;intPos: Integer;begin//如果列表没有节点则退出if RzTreeView1.Items.GetFirstNode = nil then Exit;//以选择节点的变量判断使用什么表,这个是已知第一个节点的变量是何值,对其进行判断,如果节点则调用一个表后并退出if Pos('班级数', RzTreeView1.Selected.Text) <> 0 thenbegindm.qTempQ.Close;dm.qTempQ.SQL.Clear;dm.qTempQ.SQL.LoadFromFile('bin\selclass.sql');dm.qTempQ.SQL.Add('group by 姓名');dm.qTempQ.Open;with dm.qMTT dobeginClose;SQL.Clear;SQL.LoadFromFile('bin\selIO.sql');SQL.Add('group by 姓名');Open;end;Exit;end;//得到选择的节点的变量StrPos := RzTreeView1.Selected.Text;//对变量进行判断intPos := pos(']',StrPos);//获得一个变量StrPos := Copy(StrPos, intPos+1, Length(StrPos)-intPos);//依上个变量值调用表灵气with dm.qTemp2 dobeginClose;SQL.Clear;SQL.Add('select * from t_class where 名称=''' + StrPos + '''');Open;StrPos := fieldbyname('编号').AsString;end;//上面的调用是两表主键的使用,与treeview无关,调用出的数据在dbgrid中显示 with dm.qTempQ dobeginClose;SQL.Clear;SQL.LoadFromFile('bin\selclass.sql');SQL.Add('where 班级编号=''' + StrPos + '''');SQL.Add(' and 时间>=:d1 and 时间<=:d2');SQL.Add(' group by 姓名');Parameters.ParamByName('d1').Value := RzDateTimeEdit1.Date;Parameters.ParamByName('d2').Value := RzDateTimeEdit2.Date + 1;Open;end;with dm.qMTT dobeginClose;SQL.Clear;SQL.LoadFromFile('bin\selIO.sql');SQL.Add('where 班级编号=''' + StrPos + '''');sql.add(' and 日期时间>=''' + RzDateTimeEdit1.text + '''');sql.add(' and 日期时间<=''' + RzDateTimeEdit2.text + '''');SQL.Add(' group by 姓名');Open;end;end;。
浅谈Delphi⾼效使⽤TreeView本来我⼀直都是使⽤递归算法, 效率很低下边这段代码是我原来写的-----------------------------------------------------------------------------------------------------procedure TForm1.GetDepartmentMsg;varTest, Test2 : TTreeNode;procedure NodeAdd(Test : TTreeNode; DepartmentId : string);varTestlevel : TTreeNode;TestQuery : TADOQuery;begintryTestQuery := TADOQuery.Create(Nil);TestQuery.Connection := ADOConnection1;With TestQuery dobeginClose;SQL.Text := 'Select DepartmentID ,NAME from Department where DepartmentID like '''+DepartmentId+'%'' and Len(DepartmentId) = ' + IntToStr(Length (DepartmentId) + 2) + 'Group by DepartmentID ,name order by DepartmentID ' ;Open;if Not IsEmpty thenbeginwhile not Eof dobeginTestlevel := TreeView1.Items.AddChild(Test,TestQuery.fieldbyName('Name').AsString + ' | '+TestQuery.fieldbyName('DepartmentId').AsString);NodeAdd(Testlevel,TestQuery.fieldbyName('DepartmentId').AsString);Testlevel.ImageIndex := Testlevel.Level -1;Testlevel.SelectedIndex := Testlevel.Level -1;Next;end;end;end;finallyTestQuery.free;end;end;beginTest := TreeView1.Items.Add(nil,' ***** | 00');Test.ImageIndex := 1;with Query1 dobeginClose;Sql.Text := 'Select * from Department where State = ''正常'' and DepartmentLevel = ''1'' ';Open;end;Query1.First;TreeView1.Items.BeginUpdate;while not Query1.Eof dobeginTest2 := TreeView1.Items.AddChild(Test,Query1.fieldbyName('Name').AsString + ' | '+ Query1.fieldbyName('DepartmentId').AsString) ; NodeAdd(Test2,Query1.fieldbyName('DepartmentId').AsString);Query1.Next;end;TreeView1.Items.EndUpdate;Query1.Close;end;今天⽆事测试了这段代码时间是6-7秒左右下边这段改进后的,不使⽤递归procedure TForm1.NewGetDepartmentMsg;constDivNum = 2;varnLevel: Integer;pNodes: array[0..1023] of TTreeNode;DepartmentID, Name: string;Str: string;beginStr := 'Select DepartmentID, Name from Department order by DepartmentID';with adoquery1 dobeginClose;Sql.clear;Sql.add(Str);Open;end;TreeView1.Items.Clear;TreeView1.Items.BeginUpdate;pNodes[0] := TreeView1.Items.Add(nil, '***');if Not ADOQuery1.IsEmpty thenwhile not ADOQuery1.Eof dobeginDepartmentID := ADOQuery1.fieldbyName('DepartmentID').AsString;Name := ADOQuery1.fieldbyName('Name').AsString;nLevel := Length(DepartmentID) div DivNum ;pNodes[nLevel] := TreeView1.Items.AddChild(pNodes[nLevel - 1], DepartmentID + ' | ' + Name);ADOQuery1.Next;end;TreeView1.Items.EndUpdate;ADOQuery1.Close;end;这个算法主要合理利⽤了 'Select DepartmentID, Name from Department order by DepartmentID' 来排序, 这就保证了pNodes[nLevel] := TreeView1.Items.AddChild(pNodes[nLevel - 1], DepartmentID + ' | ' + Name);他的上级结点不为空这段代码我⼀测试, ⼤概是0.2秒左右, 数据和上边那段代码处理⼀样的数据这样写肯定是有缺陷的, 也不是什么情况下都能使⽤写得不对的地⽅,欢迎批评和指正,谢谢。
一:TreeView.Items[0].Expanded := True; // 展开第一个节点二:TreeView.Items[0].Item[0].Selected := True; // 移动到第一个节点的第一个子节点找当前节点的下一个节点,按序号找如下:if treeview1.Selected.GetNext<>nil thentreeview1.Selected.GetNext.Selected:=true;TreeView1.SetFocus;找当前节点的下一个同层兄弟如下:if treeview1.Selected.getNextSibling<>nil thentreeview1.Selected.getNextSibling.Selected:=true;TreeView1.SetFocus;TreeView.Selected.getPrevSibling //当前选中节点的上一个兄弟节点TreeView.Selected.Parent // 当前选中节点的父节点getfirstchild是跳到该节点子结点中的第一个getlastchild是跳到该节点子结点中的最后一个如果你是想跳到同层兄弟结点的第一个if treeview1.selected.parent<>nil thentreeview1.selected.parent.getfirstchild.selected:=trueelsetreeview1.items.item[0].selected:=true;如果你是想跳到同层兄弟结点的最后一个if treeview1.selected.parent<>nil thentreeview1.selected.parent.getlastchild.selected:=trueelsetreeview1.Items.Item[treeview1.Items.Count-1].Selected:=true;TreeView的使用方法基本信息:TreeView 是一个显示树型结构的控件,每一个节点都是一个新类, 使用具有代表性每个节点都有四个值:TEXT:显示文字Image Index:显示图形序号Selected Index:State Index:(1)建立目录项(本例中使用的TREEVIEW名称为:TvwTips)增加根目录下的节点:(节点)varCatNode : TTreeNode; //先建立一个TREEVIEW使用的子对象beginTvwTips.SetFocus; //将焦点置到这个TREEVIEW控件上{ 在根标题下建立一个新的子标题}CatNode := TvwTips.Items.AddChild(TvwTips.Items.GetFirstNode,'New Category' );CatNode.ImageIndex := 1;CatNode.SelectedIndex := 2;CatNode.EditText; { 允许用户改变这个标题}end;增加下一级目录(内容):varParentNode, TipNode : TTreeNode; //先建立TREEVIEW使用的子对象VersionNum : Integer;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,'NewSubject',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的第一个节点,函数类型为:TTreeNodeTvwTips.Items.Count 返回当前TreeView的全部节点数,整数TvwTips.Selected.Level 返回当前选中节点的在目录树中的级别,根目录为0TvwTips.Selected.Parent 返回当前选中节点上级节点,函数类型为:TTreeNode三、下面这段程序是用TREEVIEW连数据库及一些操作:unit bmzd;usesWindows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls, Db, DBTables, ImgList, Buttons, ExtCtrls, Grids,DBGrids;typeTfrmbmzd = 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;varfrmbmzd: Tfrmbmzd;ii:integer;tv:ttreenode;constSCodeFormat = '222222'; //科目代码结构SFirstNodeTxt = '部门分类';implementationuses dm;{$R *.DFM}function tfrmbmzd.LoadCode(crTbl:TDBDataSet):Integer; var NowID,sName,ShowTxt:String;i,Level:Integer;MyNode:array[0..6]of TTreeNode;//保存各级节点,最长支持6级(重点)beginScreen.Cursor:=crHourGlass;Level:=0;With frmdm.tabbm dobegintryif 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 dobeginNowID:=Trim(FieldByName('bumeng_id').AsString); ShowTxt:=FieldByName('bumeng_name').AsString; Level:=GetLevel(SCodeFormat,NowID);//返回代码的级数//以下是增加子项//以下用上一级节点为父节点添加子节点if Level>0 then//确保代码符合标准beginMyNode[Level]:=tvwCode.Items.AddChild(MyNode[Level-1],NowID+' '+ShowTxt);MyNode[Level].ImageIndex:=1;MyNode[Level].SelectedIndex:=2;end;//以上是增加子项Next;end;finallyClose;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;beginLevel:=-1;//如果代码不符合标准,则返回-1iLen:=0;if (sFormat<>'')and(sCode<>'')thenfor i:=1 to Length(sFormat) doiLen:=iLen+StrToInt(sFormat[i]);if Length(sCode)=iLen thenbeginLevel:=i;Break;end;end;Result:=Level;end;procedure Tfrmbmzd.FormShow(Sender: TObject);beginif 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); beginAction := caFree;end;procedure Tfrmbmzd.cmd_newClick(Sender: TObject);tvwcode.SetFocus ;if tvwcode.selected.AbsoluteIndex<>0 thenbegincmd_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 thenbeginif tvwcode.Selected.GetLastChild.index+1>9 thenedit2.text:=inttostr(tvwcode.Selected.GetLastChild.index+1)elseedit2.text:='0'+inttostr(tvwcode.Selected.GetLastChild.index+1); edit3.text:='新建部门';edit2.Enabled:=true;edit3.Enabled:=true;endelsebeginedit2.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);varI:integer;seno,setext:string;beginif tvwcode.Selected.HasChildren=true thenbeginapplication.messagebox('该部门包含下级,不能删除','提示',MB_OKCANCEL+mb_iconquestion ) ;endelsebeginif application.messagebox('你确实要删除当前部门吗','提示',MB_OKCANCEL+mb_iconquestion )=IDOKbeginsetext:=tvwcode.selected.text;i:=0;while setext[i] <> ' ' dobeginI := 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 thenbeginfrmdm.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); beginif key in ['0'..'9',Chr(vk_Back)] thenbeginkey:=#0;application.messagebox('','',mb_ok);end;end;procedure wcodeChange(Sender: TObject; Node: TTreeNode); vari,lev:integer ;strr,seno,setext:string;beginif cmd_new.Enabled =true thenbeginif tvwcode.selected.AbsoluteIndex<>0 thenbegincmd_delete.Enabled:=true;cmd_update.Enabled:=true;cmd_save.Enabled :=true;setext:=tvwcode.selected.text;i:=0;while setext[i] <> ' ' dobeginI := 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 of2: 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);endelsebeginedit1.text :='';edit2.text :='';edit3.text :='部门分类';cmd_delete.Enabled :=false;cmd_update.Enabled :=false;end;end;end;procedure Tfrmbmzd.cmd_updateClick(Sender: TObject);vari:integer;beginfor i:=0 to ComponentCount-1 dobeginif (Components[I] is tedit ) then(Components[I] as tedit).enabled:=false;end;for i:=0 to ComponentCount-1 dobeginif (Components[I] is tbitbtn ) then(Components[I] as tbitbtn).enabled:=true;end;if tvwcode.Selected.AbsoluteIndex<>0 thenbeginif 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;tryfrmdm.tabbm.Post;//表的保存excepton edbengineerror dobeginedit2.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);begincmd_new.Enabled :=false;cmd_delete.Enabled :=false;edit2.enabled:=true;edit3.Enabled :=true;end;procedure wcodeClick(Sender: TObject);vari:integer;beginif cmd_new.Enabled =false thenbeginapplication.MessageBox('当前是修改状态,请单击保存按钮','提示',mb_ok); tv.Selected :=true;end;if tvwcode.selected.AbsoluteIndex=0 thenbeginfor i:=0 to ComponentCount-1 dobeginif (Components[I] is tedit ) then(Components[I] as tedit).enabled:=false;end;for i:=0 to ComponentCount-1 dobeginif (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控件。
delphi中TTreeView的使⽤⽅法【学习万⼀⽼师博客摘要】TTreeView 与两个重要的类相关:TTreeNodes、TTreeNode 。
TTreeNodes即是TTreeView 的Items属性,TTreeNodes是TTreeNode的合集,TTreeNode代表的是TTreeView的节点,不按主从关系,节点依次存储在Items中。
TTreeView的Select⽅法⽤来指定TTreeView选择的节点,可以选择多个节点。
TTreeNodes使⽤add添加同级节点,使⽤addChild添加下级节点。
node.parent表⽰node节点的上级节点。
TTreeNode的⼀些属性:'绝对序号':Node.AbsoluteIndex'所在级别':Node.Level'在兄弟中排⾏':Node.Index'下级总数':Node.Count'上级元素':Node.Parent.text'上⼀个':Node.GetPrev.text'下⼀个':Node.GetNext.text'上⼀个兄弟':Node.GetPrevSibling.text'下⼀个兄弟':Node.GetNextSibling.text'上⼀个可见':Node.GetPrevVisible.text'下⼀个可见':Node.GetNextVisilbe.text'第⼀个下级':Node.GetFirstChild.text'最后⼀个下级':Node.GetLastChile.text'总数':Node.Ower.countTreeView的items属性可以导出为*.txt⽂件,并可从⽂件或流中导⼊,需要注意流或⽂件中的数据格式有严格要求, 要求必须是树状结构; 结构中可以⽤"空格"和"Tab"分层.treeview的插⼊、删除操作{插⼊, 只能通过 TTreeNodes}node := TreeView1.Selected;TreeView1.Items.Insert(node, '新成员');{⽤ TTreeNodes 删除}node := TreeView1.Selected;TreeView1.Items.Delete(node);{⽤TTreeNode删除}node := TreeView1.Selected;node.Delete;{删除它的所有下级}node := TreeView1.Selected;if node.HasChildren thennode.DeleteChildren。
1. 创建一个单元如下unit uDialogFindUnassignedUsersInfo;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, uDialogBase, ComCtrls, RzTreeVw, StdCtrls, Menus, ADODB, DB;typeTfrmDialogFindUnassignedUsersInfo = class(TfrmDialogBase)GroupBox1: TGroupBox;tvSystemManagerInfo: TRzTreeView;ADOConnection1: TADOConnection;procedure FormShow(Sender: TObject);procedure FormClose(Sender: TObject; var Action: TCloseAction); private{ Private declarations }public{ Public declarations }function Execute: Boolean;procedure CreateChildTree(ParentNode: TTreeNode);procedure ShowChildTree;end;typePNodeInfo = ^TNodeInfo;TNodeInfo = recordID: string;Name: string;end;varfrmDialogFindUnassignedUsersInfo: TfrmDialogFindUnassignedUsersInfo;implementationusesuDataModule;{$R *.dfm}procedure TfrmDialogFindUnassignedUsersInfo.CreateChildTree(ParentNode: TTreeNode);varadoQuery: TADOQuery;ChildNode: TTreeNode; // 孩子结点ChildNodeInfo: PNodeInfo; // 孩子结点信息ParentID: string;begininherited;adoQuery := TADOQuery.Create(nil);with adoQuery dobegintryConnection := ADOConnection1;Close;SQL.Clear;if (PNodeInfo(ParentNode.Data)^.ID = '') thenParentID := '0'elseParentID := PNodeInfo(ParentNode.Data)^.ID;SQL.Add('SELECT t_ID,t_Name FROM tbl_Test WHERE t_ParentID =' + ParentID);Open;while not Eof dobeginNew(ChildNodeInfo);ChildNodeInfo^.ID := FieldByName('t_ID').AsString;ChildNodeInfo^.Name := FieldByName('t_Name').AsString;ChildNode := tvSystemManagerInfo.Items.AddChildObject(ParentNode,ChildNodeInfo^.Name, ChildNodeInfo);CreateChildTree(ChildNode); // 进行递归Next;end;Close;excepton E: Exception doFree;end;end;end;procedure TfrmDialogFindUnassignedUsersInfo.ShowChildTree;varChildNode: TTreeNode; // 孩子结点ChildNodeInfo: PNodeInfo; // 孩子结点信息begininherited;New(ChildNodeInfo);ChildNodeInfo^.ID := '0'; // 此方法中最顶结点为0标识ChildNodeInfo^.Name := '';ChildNode := tvSystemManagerInfo.Items.AddChildObject(nil, '全部',ChildNodeInfo);CreateChildTree(ChildNode); // 进行递归tvSystemManagerInfo.FullExpand;end;procedure TfrmDialogFindUnassignedUsersInfo.FormShow(Sender: TObject); begininherited;ShowChildTree;end;procedure TfrmDialogFindUnassignedUsersInfo.FormClose(Sender: TObject; var Action: TCloseAction);begininherited;frmDialogFindUnassignedUsersInfo := nil;end;End.到此,绑定结果。
delphi中Treeview的使用介绍每一个节点下子节点形成这一节点的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表示节点被选中时图片序号。
/////////////////////////////////////////////////////////// /////delphi下treeview控件基于节点编号的访问有时我们需要保存和重建treeview控件,本文提供一种方法,通过以树结构节点的编号访问树结构,该控件主要提供的方法如下:function GetGlobeNumCode(inNode:TTreeNode):String;功能:返回当前节点的编号,编号规则见源码内说明。
function LocatOrGenerateNode(inNumCode:String):TTreeNode; 功能:以编号返回节点,假如节点的父节点和它的前继兄弟节点不存在,该方法会创建它们,名称为'Temp',当然假如已经存在,就不执行创建工作。
通过以上两个函数,这样我们就可以不加限制的创建和访问节点。
该控件在我以前开发的,现在提供给大家做一个参考,希望能对你有帮助。
源码:// ***********************************************//// 用于实现对TreeView控件的树结构的保存和重建// 编写该控件主要用于实现对行政文件等具有树的层次结构的对象// 实现保存和显示// 节点编号规则:// + ***** ->1// + ***** ->1.1// + ***** ->1.1.1// + ***** ->1.2// 作者:Jack// 最后修改日期:2002-12-24//// **********************************************unit CtrlTree;interfaceusesWindows, Messages, SysUtils, Classes, Graphics, Controls,Forms, Dialogs,ComCtrls;typeTCtrlTree = class(TTreeView)private{ Private declarations }functionGetPosAtBound(inString:String;inStart:Integer):Integer; function GetTheLastPointPos(inString:String):Integer; protected{ Protected declarations }public{ Public declarations }function GetNumInSameLevel(inNode:TTreeNode):Integer; function GetGlobeNumCode(inNode:TTreeNode):String;function GetParent(inNumCode:String):TTreeNode;functionLocateNodeInLevel(parNode:TTReeNode;LevelCode:integer):TTRe eNode;published{ Published declarations }function LocatOrGenerateNode(inNumCode:String):TTreeNode;functionInsertAsFinalChild(inString:String;inNode:TTreeNode):TTReeN ode;functionInsertAsPreviousSibling(inString:String;inNode:TTreeNode):T TReeNode;end;procedure Register;implementationprocedure Register;beginRegisterComponents('Standard', [TCtrlTree]);end;{ TCtrTree }function TCtrlTree.GetNumInSameLevel(inNode: TTreeNode): integer;{功能:产生已存在节点在兄弟节点层中对应的编号,从1起编入口参数:inCode:TTreeNode节点返回:同层编号}vari:integer;tmp:TTreeNode;begini:=0;tmp:=inNode;while tmp<>nil dobegintmp:=tmp.getPrevSibling;i:=i+1;end;Result:=i;end;function TCtrlTree.GetGlobeNumCode(inNode: TTreeNode): string;{功能:产生已存在节点对应的全局编号入口参数:inCode:TTreeNode节点返回:全局编号}varnocode:string;tmp:TTreeNode;begintmp:=inNode;nocode:=IntToStr(GetNumInSameLevel(tmp));while tmp.Level<>0 dobegintmp:=tmp.Parent;nocode:=inttostr(GetNumInSameLevel(tmp))+'.'+nocode;end;Result:=nocode;end;function TCtrlTree.LocatOrGenerateNode(inNumCode: String): TTreeNode;{功能:根据提供的全局编号进行定位,如路径不全,则创建路径在定位过程产生的节点的Text为Temp最终返回对应于全局编号的子节点入口参数:inNumCode:String为全局编号返回:全局编号对应的字节点}vari,j:Cardinal;NumInLevel:integer;tmp:TTreeNode;par:TTreeNode;begintmp:=nil;i:=1;while i<=StrLen(PChar(inNumCode)) dobegin//得到下一个点号的开始位j:=GetPosAtBound(inNumCode,i);//得到在兄弟节点中的排行数NumInLevel:=StrToInt(Copy(inNumCode,i,j-i+1));//定位父节点par:=GetParent(Copy(inNumCode,1,j));//得到对应的节点tmp:=LocateNodeInLevel(par,numInLevel);i:=j+2;end;Result:=tmp;end;function TCtrlTree.GetParent(inNumCode: String): TTreeNode; {功能:根据提供的全局编号找到对应的父节点如果是第一层的节点,则父节点为nil入口参数:inNumCode:String为全局编号返回:全局编号对应的父节点}varGoStep:integer;i:integer;j:integer;k:integer;SearChInNode:TTReeNode;ReturnNode:TTReeNode;begin//是第一层节点,返回nil;k:=GetTheLastPointPos(inNumCode);if k=0 thenbeginResult:=nil;Exit;end;//是第二层或第二层以上节点i:=1;SearchInNode:=Items.GetFirstNode;while i < GetTheLastPointPos(inNumCode) do beginj:=GetPosAtBound(inNumCode,i);GoStep:=StrToInt(Copy(inNumCode,i,j-i+1));if i=1 then //在第一层节点中搜索beginReturnNode:=SearchInNode;for k:=1 to GoStep-1 doReturnNode:=ReturnNode.getNextSibling;endelse //在第二层或第二层以上节点中搜索beginGoStep:=StrToInt(Copy(inNumCode,i,j-i+1)); ReturnNode:=SearchInNode.Item[GoStep-1];end;SearchInNode:=ReturnNode;i:=j+2end;Result:=SearchInNode;end;function TCtrlTree.LocateNodeInLevel(parNode: TTReeNode;LevelCode: integer): TTReeNode;{功能:根据父节点以及在兄弟节点中的编号找到对应的节点如果要创建兄弟及自己,则新创建的节点的Text为Temp入口参数:parNode: TTReeNode为父节点LevelCode: integer为编号返回:在parNode中编号为LevelCode的孩子节点}vari:integer;j:integer;tmp:TTreeNode;tmps:TTreeNode;begin//父节点为空,是第一层节点tmp:=nil;if parNode=nil thenbegini:=1;tmps:=Items.GetFirstNode;while (tmps<>nil) and (i<=LevelCode) do begintmp:=tmps;tmps:=tmps.getNextSibling;i:=i+1;end;i:=i-1;for j:=1 to LevelCode-i dotmp:=Items.AddChild(nil,'Temp');Result:=tmp;endelse //父节点不为空,正常处理beginif parNode.Count for i:= 1 to LevelCode-parNode.Count do Items.AddChild(parNode,'Temp');Result:=parNode.Item[LevelCode-1];end;end;function TCtrlTree.GetPosAtBound(inString:String;inStart:Integer): Integer;{功能:根据起始位置找到下一个'.'的前一个位置入口参数:inString: String节点编号inStart: Integer当前处理层次的起始位置返回:当前处理层次的结束位置}vartmp:Char;pos:integer;beginpos:=inStart+1;while pos <= Integer(StrLen(PChar(inString))) dobegintmp:=inString[pos];if tmp='.' thenBreakelsepos:=pos+1;end;Result:=pos-1;end;function TCtrlTree.GetTheLastPointPos(inString: String): Integer;{功能:找到编号中最后的'.'的位置入口参数:inString: String为节点编号返回:节点编号中最后的'.'的位置}vartmp:Char;pos:integer;beginpos:=Integer(StrLen(PChar(inString)));while pos>=1 dobegintmp:=inString[pos];if tmp='.' thenBreakelsepos:=pos-1;end;Result:=pos;end;function TCtrlTree.InsertAsFinalChild(inString: String; inNode: TTreeNode):TTReeNode;{功能:为当前节点插入一个孩子节点,位置为最后入口参数:inString: String为节点编号为待插入节点的字符串inNode: TTreeNode,当前节点}beginResult:=Items.AddChild(inNode,inString);end;function TCtrlTree.InsertAsPreviousSibling(inString: String; inNode: TTreeNode):TTReeNode;{功能:为当前节点插入一个前导的兄弟节点入口参数:inString: String为节点编号为待插入节点的字符串inNode: TTreeNode,当前节点}beginResult:=Items.AddChildFirst(inNode,inString);end;end./////////////////////////////////////////////////////////// /////delphi中treeview图标if TreeView.Items[i].parent = nil thenbeginTreeView.Items[i].ImageIndex := 0;end;if TreeView.Items[i].Text = '退出' thenbeginTreeView.Items[i].ImageIndex := 3;end;通过这种方式,设几种图标都行/////////////////////////////////////////////////////////// /////在Delphi 6 IDE中,最显眼的新功能可能就是Object TreeView了。