delphi中TreeView控件使用.doc_第1页
delphi中TreeView控件使用.doc_第2页
delphi中TreeView控件使用.doc_第3页
delphi中TreeView控件使用.doc_第4页
delphi中TreeView控件使用.doc_第5页
已阅读5页,还剩12页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

DELPHI中利用TreeView控件建立目录树2000-06-26 00:00:00 中国计算机报社pRainbow的话:关于TreeView的使用,还可以参看:联合使用TreeView 组件TreeView是一个显示树型结构的控件,通过它能够方便地管理和显示具有层次结构的信息,是Windows应用程序的基本控件之一。DELPHI虽然具有比较强大的文件管理功能,提供了多个用于文件管理的标准控件,如DriveComboBox、DirectoryListBox、FileListBox等,通过设置它们的属性,使其建立起联系,甚至不用编写一行程序,我们就可以实现在不同的目录之间进行切换,然而这样的目录切换只适用于进行文件的查找定位,而不能方便地进行目录的浏览,例如我们要从c:windows目录转到c:program files目录,就必须返回到根目录才能进行切换,而不能象Windows资源管理器那样任意地在不同的目录之间进行浏览与切换。 要实现在不同目录之间任意切换和浏览,还是需要使用TreeView控件,以下程序就利用DELPHI的TreeView控件来建立目录树。 在该程序中采用的各部件以及界面设计如下图所示: 各部件的主要属性设置如下: 部件 属性属性值formname captionform1 目录浏览drivecommbobox name visibledrivecommbobox1 falsefilelistboxname visiblefiletype filelistbox1falsefddirectoryimagelist name imagelist1treeview name images 该程序利用DriveCommboBox控件来获得系统具有的驱动器,并以此作为目录树的最上层,利用FileListBox控件,通过设置其Filetype属性为fdDirectory,可以获得所需的子目录,在TreeView控件的OnExpanding事件中将得到的子目录加到该控件的某一节点下。 整个程序的源代码如下: unit main; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,StdCtrls, FileCtrl, ComCtrls, ImgList; type TForm1 = class(TForm) DirTreeView: TTreeView; FileListBox1: TFileListBox; DriveComboBox1: TDriveComboBox; ImageList1: TImageList; procedure FormCreate(Sender: TObject); procedure DirTreeViewExpanding(Sender: TObject; Node: TTreeNode;var AllowExpansion: Boolean); private Private declarations public Public declarations end; var Form1: TForm1; implementation $R *.DFM procedure TForm1.FormCreate(Sender: TObject); var FirstNode,DirNode : TTreeNode; ItemCount,Index:integer; Itemstr:string; begin ItemCount:= DriveComboBox1.Items.Count; /所有驱动器的个数 FirstNode := DirTreeView.Items.GetFirstNode; for index := 0 to ItemCount -1 do begin ItemStr:= DriveComboBox1.Itemsindex; ItemStr:= copy(ItemStr,1,pos(:,ItemStr) ; /获得驱动器的名称(比如C/D) DirNode := DirTreeView.Items.AddChild(FirstNode, ItemStr ); DirNode.HasChildren := true; DirNode.ImageIndex := 0; DirNode.SelectedIndex := 1; end; end;/响应扩展事件 procedure TForm1.DirTreeViewExpanding(Sender: TObject; Node: TTreeNode;Var AllowExpansion: Boolean); var DirNode : TTreeNode; ItemCount,Index,level,icount:integer; Itemstr,strPath:string; begin if node.Count = 0 then begin icount:=0; level:=node.Level ; dirnode:=node; strPath:=node.Text+ ; while level 0 do begin strPath:=dirnode.Parent.Text+strpath; dirnode:=dirnode.parent; level :=level -1; end; FileListBox1.Clear ; FileListBox1.Directory := strpath; ItemCount:= FileListBox1.Items.Count; for index:=0 to ItemCount -1 do begin itemstr:=filelistbox1.itemsindex; itemstr:= copy(ItemStr,2,pos(,ItemStr)-2) ; if (itemstr.) and (itemstr .) then begin DirNode := DirTreeView.Items.AddChild(Node,itemstr ); DirNode.HasChildren :=true; DirNode.ImageIndex := 0; DirNode.SelectedIndex := 1; icount:=icount+1; end; if icount = 0 then Node.HasChildren := false; end; end; end; end. 程序的运行效果如图所示:我们可以展开目录树中的任何一个节点,并且可以在任意节点之间切换,就象我们在Windows资源管理器中所作的那样,而不需要逐级回退之后才能进行切换。 我的DBTreeView-TreeView直接连接数据表 获取其他程序中TreeView的内容 在ASP.NET中使用Treeview控件和XML 利用Treeview实现树形列表 控件treeview的使用 TreeView使用笔记 取得的Outlook目录并在TTreeView里显示出来 Object TreeView简要说明 TreeView的使用Delphi中根据分类数据生成树形结构的最优方法很多系统都有类似于如下的表结构(table1):IDName ParentID-001 电子类0002金属类 0003 电容电子 001004 电阻电子 001005 有色金属002而且大家都习惯于用树(TreeView)来显示,这样就可以很好的显示整个表的分类情况。但如果数据量多时会造成树的生成比较慢,特别是用递归来实现时要访问数据库的次数很多(根据层数),用在三层中效果更加显。在此提供一个好的方法来生成树形结构。这个算法只访问一次数据库,具体的实现如下:1、一次性从数据库中取出所有的数据,并按照ParentID字段进行排序,这样就保证每一条数据的父节点都在它的前面。2、取出第一条数据画到树中,在添加到树中时先找到这条数据的父节点,如果没有 则将此记录直接作为树的第一级节点3、如果还有数据,则取出来执行第2步,直到没有数据为止。程序实现: 本程序将用一个stlID的TStringList变量来存放对应树中每一个节点的ID值,用FindParent函数来父节点。function FindParent(ID:String):TTreeNode;var i:Integer;begin result:=nil; for i:=TreeView1.Items.Count-1 downto 0 doif stlID.Stringsi=ID then begin result:=TreeView1.Itemsi; break; end;end;/生成树procedure CreateTree;var tmpNode:TTreeNode;begin Query1.close; Query1.SQL.Text:=select * from table1 order by ParentID; Query1.Open; Query1.First; while not Query1.Eof do begin tmpNode:=TreeView1.Items.AddChild(FindParent(Query1.FieldByName(ParentID).AsString),Query1.FieldByName(Name).AsString); stlID.Add(Query1.FieldByName(ID).AsString);/记录ID Query1.Next; end;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 SubNodeName1 := 便笺; SubNodeName2 := 发件箱; SubNodeName3 := 联系人; SubNodeName4 := 任务; SubNodeName5 := 日记; 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 + + SubNodeNameI; SubNode := TV1.Items.AddChildObject(RootNode, SubNodeNameI, P) ; ; / 如果不想使用图标的话请删除以下两行 SubNode.ImageIndex := I; SubNode.SelectedIndex := I; end; TV1.Items.EndUpdate; end; 二.在TreeView中如何设置选中结点 var i:integer; i为设置的选中结点的索引值 begin if itreeview1.items.count then treeview1.itemsi.selected:=true; 或 treeview1.selected:=treeview1.itemsi; 三。设置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 file :/将每个结点的文字改成为小写字母 TreeView1.itemsi.text:=lowercase(TreeView1.itemsi.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; 今天上午到现在的心得想从以下的一段代码来说明。代码很简单(当我搞完后才觉得简单,搞了半天,哎,没办法,资质有限呀),主要是要完成当双击TreeView中的一项的时候将数据库中符合条件的数据显示在一个DBGird中。 procedure TmainForm.TreeviewDblClick(Sender: TObject); var i:Integer;node:TTreeNode;beginnode:=Treeview1.Selected;if node.TextfatherthenbeginLoadGDDBGrid(node.Text);end;end;procedure TmainForm.LoadGDDBGrid(username:String);varnode1,node2:TTreeNode;SearchOptions:TLocateOptions;strSQL:String;begin strSQL := select * from user_information where user_information.USERNAME = %s ;strSQL:=Format(strSQL,username);showmessage(strSql);with ADODataSet1 dobeginClose;CommandText:=strSQL;Open;end;end;先说明第一个procedure的功能吧,TreeviewDblClick()主要就是双击后能触发DBGrid中的事件而已。这里面主要要说明的是node := Treeview1.Selected,这句话的意思就是获得目前被选中的节点,然后就可以根据node.Text来获得此时选中的节点的内容是什么了。这样的做法和我以前学习的语言有比较大的出入。这里其实也弄了好久,因为一开始是以以前自己学习的语言程序的经验来考虑,认为要获得目前选中的内容的话,应该使用的是Treeview中的item,当然,也可以通过这个来获得,但它却需要告诉程序是哪个item(itemi),这显然就不符合现在需要做的效果了。目前需要做的应该是先找到一种方法能够让程序知道我目前选择的是哪个节点,然后就找了一下Treeview1中有哪些方法,发现了Selected,但看到它的返回值是一个note,这就让我有点迷惑了,为什么返回的不是一个item呢(这主要是因为对delphi的体系仍然没有一个很好的了解和总结),后来发觉在note里面也有一种方法是text的,然后试了一下,就获得了我所需用的效果了。现在想了想,其实以前已经知道Treeview是由一个个的note组成的,想到这个,就觉得note.text是很理所当然的了。 花时间最多的可能是第二段代码吧,LoadGDDBGrid()主要是把符合条件的数据显示到DBGrid中去。首先,我需要解决的是如何能让数据显示出来,我想到了在设计界面上DBGrid有一个DataSet的属性选择,那里选择的是ADODataSet1(ADODataSet类型),然后想起前两天连接数据库的时候只要将ADODataSet1中的Active设置成True的话,Grid就会自动显示相应的数据。那么,我只要把ADODataSet1激活的话,就应该可以把数据显示出来了,于是就使用了ADODataSet1.Active := True,确实,可以把它显示出来了。但这种显示是把所有数据都显示出来,那么,下一步需要解决的就是如何变为可以根据条件显示了。在ADODataSet1中有一个CommandText,是用来保存该ADODataSet所运行的sql语句的,那么又从这里开始入手。到了这里,遇到的困难竟然是一个以前不算是困难的问题。以前在使用java的时候,由于java的String是使用双引号来包括的,比如A=a,但现在的delphi却是使用单引,郁闷呀,因为我的where后面的field是varchard类型的,如果在java中就可以表示为A=a,但在delphi中就让我困惑了,这里搞了一阵子,最后才发觉只要在其中加多两个单引就可以了,如A=a,呵呵,让我哭笑不得。 在写这个功能的时候遇到的问题大概就是这些。但我还想讲一下几个地方,首先是with ADODataSet1 do的使用,其实也就是对ADODataSet1进行了引用,那么,在这个引用中就不需要再ADODataSet1.Close这样的写关闭命令了,只需要加close就可以了。其次是Format的使用。Format()函数是用来定义字符串。它的基本格式是S := Format(My name is %s and Im %d years old., jag,26),得到的S的结果就是My name is jag and Im 26 years old.从这里可以看出了吧,Format的左右其实就是把符合条件的值放入相应的位置。%s这种就是格式化指示符。c代表字符类型,d代表整数类型,f代表浮点类型,p代表指针类型,s代表字符串类型。Delphi中树型控件的使用技巧我们都知道,开发者主要用Delphi来开发数据库管理软件,正因如此,树型控件的使用最好与数据库联系起来。Delphi提供了一个树型控件TTreeView,可以用来描述复杂的层次关系。 树节点信息的存储和加载 常用的方法是用树控件的 LoadFromFile和SavetoFile方法,来实现树控件和文件之间的交互;或用Assign方法实现树控件和DBMemo,也就是和数据库间的交互。该方法的优点是编程相对简单,缺点是树控件的实际节点数可能会很大,对于“大树”,每次加载和存储的数据量会加大,将降低速度,增大系统开销,造成数据冗余。另一种方法,就是只在树上产生“看得见”的节点,没有专门记录全部树节点结构的文件或数据库字段,而将树节点结构分散在数据库的每一个记录中。 具体方法是:创建一个数据库,字段根据实际业务而定,其中必然有一个字段的信息将在树型控件的节点上显示,另外还要一个字段来保存节点的惟一标识号,该标识号由长度相等的两部分组成,前段表示当前节点的父节点号,后段表示当前节点的节点号,此标识号相当于一个“链表”,记录了树上节点的结构。该方法的优点:用户操作“大树”时,一般不会展开所有的节点,而只用到有限的一部分,同时只能从树根一层一层地展开,该法只在树上产生“看得见”的节点,所以,存储和加载“大树”的速度快,数据量小,系统开销和数据冗余较小。缺点:编程较复杂,但可以结合该方法编成一个新的树控件,将大大提高编程效率。值得注意的是,ID号必须惟一,所以在编程中如何合理产生ID尤为重要。 数据库结构示例 创建一个数据库,为简化程序,我只创建两个数据库字段,定义如下:字段名类型长度textc10longidc6 LongID字段实际上由两段组成,每一段3位,LongID只能表示1000条记录。将LongID定义为索引字段,存为c:testtreetree.dbf。编辑该DBF文件,新建一条记录,Text字段设为TOP,LongID字段设为“000”(3个“0”前为三个空格)。 创建演示程序 在Form1上放置TreeView1、Table1、PopupMenu1、Edit1、Edit2。TreeView1的PopupMenu属性设为PopupMenu1;Table1的DataBaseName属性设为c:testtree,TableName属性设为tree.dbf,IndexFieldNames属性设为LongID;为PopupMenu1加选单项Add1和Del1,Caption分别为Add和Del;Edit1用来输入新节点的Text属性值,Edit2用来输入新节点的3位ID号。存为c:testtreetreeunit.pas和c:testtreetesttree.dpr。 在treeunit.pas的Type关键字后加入一行:Pstr:string;Pstr为字符串指针 为Form1的OnCreate事件添加代码: procedure TForm1.FormCreate(Sender: TObject); var p:Pstr;Node:TTreeNode; begin with Table1,Treeview1 do begin open; first; new(p);为指针p分配内存 p:=FieldByName(LongID).AsString; Node:=Items.AddChildObject(nil,FieldByName(Text).AsString,p); if HasSubInDbf(Node) then Items.AddChildObject(Node, ,nil);有子节点则加一个空子节点 end; end; HasSubInDbf为自定义函数,自变量为Node,检查节点Node有无子节点,有则返回True,反之返回False,并在TForm1的类定义里加入原型声明(其它自定义函数的原型也在TForm1的类定义里声明,不另作解释),函数代码如下: function TForm1.HasSubInDbf(Node:TTreeNode):Boolean; begin with Table1 do begin Table1.FindNearest(copy(Pstr(Node.Data),4,3)000); result:=copy(FieldByName(LongID).AsString,1,3)=copy(Pstr(Node.Data),4,3);如数据库里当前记录的LongID字段内容的前3位和节点Node的Data的后3位相同,则Node应该有子节点 end; end; 为TreeView1控件的OnDeletion事件添加代码,需要指出的是,不仅调用Delete方法可以触发OnDeletion事件,而且当树控件本身被释放前,也触发OnDeletion事件,所以,在此处加入dispose(node.data)会很“安全”: procedure TForm1.TreeView1Deletion(Sender: TObject; Node: TTreeNode); begin Dispose(Node.Data);释放节点数据内存 end; 为Add1选单项的OnClick事件添加代码如下: procedure TForm1.Add1Click(Sender: TObject); var p:pstr;Tmpstr:string;i:integer; begin try StrToInt(Edit2.Text); Tmpstr:=Edit2.Text;注:在实用中,必须用更好的方法来产生ID except; ShowMessage(重新输入Edit2的内容); abort; end; with TreeView1 do begin new(p); p:=copy(Pstr(Selected.Data),4,3)TmpStr; Items.AddChildObject(Selected,Edit1.Text,p); end; with Table1 do 在数据库里添加记录 begin Append; FieldByName(Text).AsString:=Edit1.text; FieldByName(LongID).AsString:=p; Post; end; TmpStr:=inttostr(strtoint(TmpStr)1); for i:=length(TmpStr) to 2 do TmpStr:=0TmpStr; Edit2.Text:=TmpStr; end; 为Del1菜单项的OnClick事件添加代码如下: procedure TForm1.Del1Click(Sender: TObject); var DelList:TStringList;LongID,NSubLongID:string; begin DelList:=TStringList.create; DelList.Sorted:=True; DelList.Add(Pstr(TreeView1.Selected.Data); while DelList.Count0 do begin LongID:=DelList.Strings0; DelList.Delete(0); Table1.SetKey; Table1.FieldByName(LongID).AsString:=LongID; if Table1.GotoKey then Table1.Delete; if HasSubInDbf(TreeView1.Sel

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论