線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:1947
推到 Plurk!
推到 Facebook!

delphi中樹型控制項的使用技巧

 
jackkcg
站務副站長


發表:891
回覆:1050
積分:848
註冊:2002-03-23

發送簡訊給我
#1 引用回覆 回覆 發表時間:2002-10-30 09:26:28 IP:61.221.xxx.xxx 未訂閱
此為轉貼資料 delphi中樹型控制項的使用技巧 作者: 檀革勤 我們都知道,開發者主要用delphi來開發資料庫管理軟體,正因如此,樹型控制項的使用最好與資料庫聯繫起來。delphi提供了一個樹型控制項ttreeview,可以用來描述複雜的層次關係。 樹節點資訊的存儲和載入 常用的方法是用樹控制項的 loadfromfile和savetofile方法,來實現樹控制項和文件之間的交互;或用assign方法實現樹控制項和dbmemo,也就是和資料庫間的交互。該方法的優點是編程相對簡單,缺點是樹控制項的實際節點數可能會很大,對於“大樹”,每次載入和存儲的資料量會加大,將降低速度,增大系統開銷,造成資料冗餘。另一種方法,就是只在樹上?生“看得見”的節點,沒有專門記錄全部樹節點結構的文件或資料庫欄位,而將樹節點結構分散在資料庫的每一個記錄中。 具體方法是:創建一個資料庫,欄位根據實際業務而定,其中必然有一個欄位的資訊將在樹型控制項的節點上顯示,另外還要一個欄位來保存節點的惟一標識號,該標識號由長度相等的兩部分組成,前段表示當前節點的父節點號,後段表示當前節點的節點號,此標識號相當於一個“鏈表”,記錄了樹上節點的結構。該方法的優點:用戶操作“大樹”時,一般不會展開所有的節點,而只用到有限的一部分,同時只能從樹根一層一層地展開,該法只在樹上?生“看得見”的節點,所以,存儲和載入“大樹”的速度快,資料量小,系統開銷和資料冗餘較小。缺點:編程較複雜,但可以結合該方法編成一個新的樹控制項,將大大提高編程效率。值得注意的是,id號必須惟一,所以在編程中如何合理?生id尤?重要。 資料庫結構示例 創建一個資料庫,?簡化程式,我只創建兩個資料庫欄位,定義如下: 欄位名 類型 長度 text c 10 longid c 6 longid欄位實際上由兩段組成,每一段3位,longid只能表示1000條記錄。將longid定義?索引欄位,存?c:\testtree\tree.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:\testtree\treeunit.pas和c:\testtree\testtree.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:=′0′+tmpstr; 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.count> 0 do begin longid:=dellist.strings[0]; dellist.delete(0); table1.setkey; table1.fieldbyname(′longid′).asstring:=longid; if table1.gotokey then table1.delete; if hassubindbf(treeview1.selected) then begin nsublongid:=table1.fieldbyname(′longid′).asstring; while (copy(nsublongid,1,3)=copy(longid,4,3))and(not table1.eof) do begin dellist.add(nsublongid); table1.next; nsublongid:=table1.fieldbyname(′longid′).asstring; end; end; end; dellist.free; treeview1.items.delete(treeview1.selected); end; ?treeview1的onexpanding事件添加代碼: procedure tform1.treeview1expanding(sender: tobject; node: ttreenode; var allowexpansion: boolean); var tmpnode:ttreenode;nsublongid:string;p:pstr;bm:tbookmark; begin with table1,treeview1 do begin items.beginupdate; setkey; fieldbyname(′longid′).asstring:=pstr(node.data)^; if not gotokey then items.delete(node) else begin tmpnode:=node.getfirstchild; if (tmpnode.text=′ ′)and(tmpnode.data=nil) then begin tmpnode.delete; if hassubindbf(node) then begin nsublongid:=fieldbyname(′longid′).asstring; while (copy(nsublongid,1,3)=copy(pstr(node.data)^,4,3))and(not eof) do begin new(p); p^:=fieldbyname(′longid′).asstring; bm:=getbookmark; tmpnode:=items.addchildobject(node,fieldbyname(′text′).asstring,p); if hassubindbf(tmpnode) then items.addchildobject(tmpnode,′ ′,nil); gotobookmark(bm); freebookmark(bm); next; nsublongid:=fieldbyname(′longid′).asstring; end; end; end; end; items.endupdate; end; end; 以上簡要談了談資料庫的樹狀顯示的基本方法,另外,編輯樹上節點的text屬性的同時對資料庫進行修改、同一資料庫在多用戶同時操作時資料庫以及樹的一致性、樹上節點的拷貝與複製等就不再贅述,讀者可自行完善。本文程式在dlphi4.0、windows 98下調試通過。
------
**********************************************************
哈哈&兵燹
最會的2大絕招 這個不會與那個也不會 哈哈哈 粉好

Delphi K.Top的K.Top分兩個字解釋Top代表尖端的意思,希望本討論區能提供Delphi的尖端新知
K.表Knowlege 知識,就是本站的標語:Open our mind
系統時間:2024-07-04 20:17:47
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!