Treeview的問題 |
答題得分者是:timhuang
|
yezi_ji
一般會員 發表:16 回覆:31 積分:9 註冊:2003-03-22 發送簡訊給我 |
請教個大大,我想把資料庫的Matetype(數據表)里數據讀到Treeview里,Matetype的結構為:Typecode(類別號),type(類別名稱),Parentcode(有無父節點),Havechild(有無子節點)。並且數據表里有三類數據(大類,中類,小類)我想用遞歸運算,但是只能出現一個節點,如下:
產品分類
---酒
---白酒
我的程式如下:
procedure TForm1.viewtree(i:Integer);
begin
Treeview1.Items.AddObject(nil,'產品分類',nil);
with ADOQuery1 do
begin
Close;
SQL.Clear;
SQL.Add('SELECT * FROM MateType WHERE Parentcode=''' inttostr(i) '''');
Open;
First;
while not eof do
begin
if FieldByName('Parentcode').AsInteger=i then
begin
Treeview1.Items.AddChildObject(Treeview1.items[i],FieldByName('Type').AsString,pchar(FieldByName('Typecode').AsString));//line12
if FieldByName('Havechild').AsInteger<>0 then
begin
viewtree(FieldByName('Typecode').AsInteger);
end;
end;
next;
end;
end;
end;
我知道是程式的line12這行的Treeview1.items[i]的問題,但是不知道怎麽表示才能使程式有效運行。 我是菜鳥,請多指點!
不勝感激!!
|
andersonhsieh
版主 發表:33 回覆:531 積分:439 註冊:2002-06-10 發送簡訊給我 |
引言: 請教個大大,我想把資料庫的Matetype(數據表)里數據讀到Treeview里,Matetype的結構為:Typecode(類別號),type(類別名稱),Parentcode(有無父節點),Havechild(有無子節點)。並且數據表里有三類數據(大類,中類,小類)我想用遞歸運算,但是只能出現一個節點,如下: 產品分類 ---酒 ---白酒 我的程式如下: procedure TForm1.viewtree(i:Integer); begin Treeview1.Items.AddObject(nil,'產品分類',nil); with ADOQuery1 do begin Close; SQL.Clear; SQL.Add('SELECT * FROM MateType WHERE Parentcode=''' inttostr(i) ''''); Open; First; while not eof do begin if FieldByName('Parentcode').AsInteger=i then begin Treeview1.Items.AddChildObject(Treeview1.items[i],FieldByName('Type').AsString,pchar(FieldByName('Typecode').AsString));//line12 if FieldByName('Havechild').AsInteger<>0 then begin viewtree(FieldByName('Typecode').AsInteger); end; end; next; end; end; end; 我知道是程式的line12這行的Treeview1.items[i]的問題,但是不知道怎麽表示才能使程式有效運行。 我是菜鳥,請多指點! 不勝感激!!可否將將你的資料表的結構post上來..... @@~~飛翔在天際的精靈~~@@
------
@@~~飛翔在天際的精靈~~@@ |
yezi_ji
一般會員 發表:16 回覆:31 積分:9 註冊:2003-03-22 發送簡訊給我 |
表MateType結構:
Key-----Name----------DataType----Size----Null
是------TypeCode------decimal-----9-------不可 //商品類別碼
--------Type----------char--------20------不可 //商品類別名稱
--------ParentCode----int---------4-------可 //父類別碼
--------Havechild-----int---------4-------可 //有無子類
其它字段沒有什麽用的。
比如説:
1(類別碼)----酒(名稱)----0(父類為無)----1(有子類)
2 ------------煙 ----------0 --------------1
101-----------白酒---------1---------------1
10101---------米酒---------101-------------0(無子類)
10102---------曲酒---------101 ------------0
數據就是這樣的,我想酒和煙為大類,酒類下有白酒,白酒下有子節點米酒和曲酒,我的意思就是這樣。
謝謝! 我是菜鳥,請多指點!
不勝感激!! 發表人 - yezi_ji 於 2003/04/04 09:12:35
|
timhuang
尊榮會員 發表:78 回覆:1815 積分:1608 註冊:2002-07-15 發送簡訊給我 |
Hi, 約略的寫法如下:
procedure TForm1.Button2Click(Sender: TObject); begin AddChildNode( nil, 0, 'root' ); end; function TForm1.AddChildNode(node: TTreeNode; typecode: integer; stype: string): TTreeNode; var Qry: TQuery; begin Result := TreeView1.Items.AddChild(node, stype); Qry:= TQuery.Create(self); Qry.DatabaseName := Database1.DatabaseName ; Qry.Close; Qry.SQL.Clear; Qry.SQL.Text := 'SELECT * FROM MateType WHERE ParentCode = ' IntToStr(typecode); Qry.Open; While not Qry.Eof do begin AddChildNode(Result, Qry.FieldByName('typecode').AsInteger, Qry.FieldByName('type').AsString); Qry.Next; end; Qry.Free; end;其中的 AddChildNode 是 遞迴 的呼叫. 請自行試試!! |
yezi_ji
一般會員 發表:16 回覆:31 積分:9 註冊:2003-03-22 發送簡訊給我 |
|
Justmade
版主 發表:94 回覆:1934 積分:2030 註冊:2003-03-12 發送簡訊給我 |
|
yezi_ji
一般會員 發表:16 回覆:31 積分:9 註冊:2003-03-22 發送簡訊給我 |
試過了,就是我是用ADOQuery做的查詢,其他的一模一樣,但是只能做一層,就是這樣的: 產品資料
----酒
--------白酒
-------------米酒
後面就沒有了
我想做的: 產品資料
------酒
----------白酒
---------------米酒
---------------曲酒
------煙
----------國產煙
---------------硬盒
---------------軟盒
----------進口煙 等等.
有了一個方向,但是我還是不知怎麽做。 我是菜鳥,請多指點!
不勝感激!!
|
Justmade
版主 發表:94 回覆:1934 積分:2030 註冊:2003-03-12 發送簡訊給我 |
|
timhuang
尊榮會員 發表:78 回覆:1815 積分:1608 註冊:2002-07-15 發送簡訊給我 |
Hi, 若是改為 ADO 的話, 寫法如下:
記得利用 TADOConnection 與資料庫建立連結.
procedure TForm1.Button2Click(Sender: TObject); begin AddChildNode( nil, 0, 'root' ); end; function TForm1.AddChildNode(node: TTreeNode; typecode: integer; stype: string): TTreeNode; var Qry: ADOQuery; begin Result := TreeView1.Items.AddChild(node, stype); Qry:= ADOQuery.Create(self); Qry.Connection := ADOConnection1; Qry.Close; Qry.SQL.Clear; Qry.SQL.Text := 'SELECT * FROM MateType WHERE ParentCode = ' IntToStr(typecode); Qry.Open; While not Qry.Eof do begin AddChildNode(Result, Qry.FieldByName('typecode').AsInteger, Qry.FieldByName('type').AsString); Qry.Next; end; Qry.Free; end;其中的 紅色部分為修改為 ADO 的版本, 請再自行試試!! |
yezi_ji
一般會員 發表:16 回覆:31 積分:9 註冊:2003-03-22 發送簡訊給我 |
|
Justmade
版主 發表:94 回覆:1934 積分:2030 註冊:2003-03-12 發送簡訊給我 |
這個就比較複雜了,因為你若不一次 Load 所有資料而等使用者按某一個節點才 Load 該等點的子代,先決條件是你可以在使用者按讓節點時找到該Typecode。可是你現在的做法只是將 Type 記住並沒有將 TypeCode 記住。 有兩個做法:
1. 若你的 Type (類別名稱) 是完全不會重覆的,那你可以用 Node.Text 來 Lookup 回 TypeCode
2. 使用 Node.Data 來儲存資料,因於這是 pointer 來的,所以你要用 pointer 形態如 PChar 等 記得要將程式改為不要不斷重覆呼叫自己。
|
timhuang
尊榮會員 發表:78 回覆:1815 積分:1608 註冊:2002-07-15 發送簡訊給我 |
引言: 但是現在又有個問題,就是速度太慢,因?我有好多節點和子節點,大概要花15秒它才出現,看了一些資料,說可以先只讀取一到兩個子節點的?容,等到用戶選擇時再顯示其他?容,但是我不知到怎?做,請幫忙。 在這再次感謝兩位,感謝你們的幫忙。修改一下程式, 將原來的全部展開改為只往下展開兩層, 另外利用 node.data 來記錄該節點的下兩層是否已展開過及該節點的 typecode, 以利後續的 onExpanding event 的檢驗來進行動態的往下展開. 為什麼使用往下展兩層, 原因是使有子節點的 node 前面都有+號存在, 以免無法觸發 onExpanding event! 程式碼如下: // 在 type 段加入 type TmyData = record expanded: boolean; typecode: integer; end; pNodeData = ^TmyData; // ..... // // procedure TForm1.Button2Click(Sender: TObject); begin AddChildNode( nil, 0, 'root', 2 ); end; // // // function TForm1.AddChildNode(node: TTreeNode; typecode: integer; stype: string; ideep: integer): TTreeNode; var Qry: TADOQuery; p: pNodeData; begin if ideep <= 0 then begin Result := nil; exit; end; New(p); p^.typecode := typecode; p^.expanded := false; Result := TreeView1.Items.AddChildObject(node, stype, p); Qry:= TADOQuery.Create(self); Qry.Connection := ADOConnection1; Qry.Close; Qry.SQL.Clear; Qry.SQL.Text := 'SELECT * FROM MateType WHERE ParentCode = ' + IntToStr(typecode); Qry.Open; While not Qry.Eof do begin AddChildNode(Result, Qry.FieldByName('typecode').AsInteger, Qry.FieldByName('type').AsString, ideep - 1); Qry.Next; end; Qry.Free; end; // // // function TForm1.AddChildNodeSub(node: TTreeNode; typecode, ideep: integer): TTreeNode; var Qry: TADOQuery; begin Qry:= TADOQuery.Create(self); Qry.Connection := ADOConnection1; Qry.Close; Qry.SQL.Clear; Qry.SQL.Text := 'SELECT * FROM MateType WHERE ParentCode = ' + IntToStr(typecode); Qry.Open; While not Qry.Eof do begin AddChildNode(node, Qry.FieldByName('typecode').AsInteger, Qry.FieldByName('type').AsString, ideep - 1); Qry.Next; end; Qry.Free; end; // // // procedure TForm1.TreeView1Expanding(Sender: TObject; Node: TTreeNode; var AllowExpansion: Boolean); var i: integer; begin // showmessage( inttostr( pNodeData(Node.Data)^.typecode )); if not pNodeData(Node.Data)^.expanded then // 檢驗是否已展開過下兩層 begin pNodeData(Node.Data)^.expanded := true; for i:= 0 to node.Count-1 do AddChildNodeSub( node.Item[i], pNodeData(node.Item[i].Data)^.typecode, 2 ); end; end; |
yezi_ji
一般會員 發表:16 回覆:31 積分:9 註冊:2003-03-22 發送簡訊給我 |
|
yezi_ji
一般會員 發表:16 回覆:31 積分:9 註冊:2003-03-22 發送簡訊給我 |
|
timhuang
尊榮會員 發表:78 回覆:1815 積分:1608 註冊:2002-07-15 發送簡訊給我 |
引言: 請問timhuang:AddChildNodeSub這個函數是幹什麽用的?Node.Data裏面到底是什麽内容,怎麽使用的? 謝謝!AddChildNodeSub 的用途與原來 AddChildNode 的不同處在於 AddChildNode 會新增傳入的節點, 而 AddChildNodeSub 則不會加入傳入的節點, 僅處理其子節點而已, 為避免程式過度複雜, 所以將 AddChildNodeSub 由 AddChildNode 分離出來, 其實是可以共用的, 只是要注意避開不產生傳入節點的產生即可!! 至於 Node.Data 本身是一個 pointer , 其目的在於儲存資料, 為什麼要利用 pointer 來作為儲存資料的 member data 呢? 因為 pointer 可以指向自定的任何型別的資料, 如此例就是利用 TmyData 這個資料來儲存著該節點的兩個資料, typecode, expanded, 利用 record 來作為 Node.Data 指向的資料, 如此一來, 任何一個節點的資訊都可以放在 Node.Data 所指向的資料了. 這是 Node.Data 的主要功能, 你也可以想想看要放什麼資料進去都可以. 用法就如同我舉的例子一般, 宣告一個 record (TmyData), 裡面放著你要存的資料, 接著宣告該資料的指標 pNodeData = ^TmyData, 其意義是說 pNodeData 是一種指向 TmyData 的指標 (pointer), 記得是指標, 不是實體資料, 所以在使用前要先使用 New 來配置記憶體給該 TmyData, 宣告 p 為 pNodeData, 再利用 New(p) 就可以配置記憶體, 使 p 指標所指向的位置就是該記憶體的位置, 使用其資料的方式就是 p^.typecode, 及 p^.expanded, 接下來我將原來的 AddChild 改為 AddChildObject 其不同處在於: function AddChild(Node: TTreeNode; const S: string): TTreeNode; function AddChildObject(Node: TTreeNode; const S: string; Ptr: Pointer): TTreeNode; AddChildObject 多給了 pointer 進去, 所以 AddChild 後再設定 Data 與直接給定其 Data 是一樣的, 以下的程式碼用來說明這兩種的結果是相同的: // case 1 p: pNodeData; New(p); Result := xxx.AddChild(n1, '1234'); Result.Data := p; // case 2 p: pNodeData; New(p) Result := xxx.AddChildObject(n1, '1234', p);其結果都是新增節點後, 並將 p 設定給 Result.Data 之中. 這樣說明就應該比較清楚了!! |
yezi_ji
一般會員 發表:16 回覆:31 積分:9 註冊:2003-03-22 發送簡訊給我 |
|
superm
一般會員 發表:1 回覆:2 積分:0 註冊:2003-05-11 發送簡訊給我 |
我是初學者
感謝.我找了好久終於由這篇文章成功完成了dbtree的結構
可是最近有一些問題.可取得刪除的位置.可是刪資料時都是只有一筆.要如何才可以批次刪
還請各位高手指點
程式碼如下:
procedure Tform1.delClick(Sender: TObject);
var
node:TTreenode;
begin
delnode(Treeview1.Selected);
end;
procedure Tform1.addClick(Sender: TObject);
var
Qry: TADOQuery;
node : TTreeNode;
index:string;
begin
node:=treeview1.selected;
treeview1.Items.addchild(node,'未命名');
index:= inttostr(pNodeData(Node.Data)^.typecode);
with adotable1 do// 在資料庫裏添加記錄
begin
append;
fieldbyname('type').asstring:='未命名';
fieldbyname('Parentcode').asstring:=index;
post;
end;
end;
function TForm1.delnode(node1:TTreenode):TTreenode;
var
childnode:TTreenode;
index:string;
Qry: TADOQuery;
begin
childnode:=node1.GetLastChild; //按倒序取得子點,因刪除節點,列表會產生變化
while childnode<>nil do
childnode:=delnode(childnode); //如子項不為空,進行遞迴調用
index:=inttostr(pNodeData(node1.data).typecode); //得該節點對應指標在數據庫刪除相應指標;
showmessage(index);{可得到刪除點的資料,可是資料庫不會寫,用下面的方法只可刪一節點就有錯誤}
result:=node1.parent.GetPrevChild(node1); //定位到刪除點的上一節點節點
node1.delete; //刪除樹節點
Qry:= TADOQuery.Create(self);
Qry.Connection := ADOConn;
Qry.Close;
Qry.SQL.Clear;
Qry.SQL.Text := 'delete FROM MateType WHERE typeCode = ' index;
Qry.Open;
Qry.Next;
Qry.Free;
end;
請高手指導.感激不盡
|
airomeo
一般會員 發表:1 回覆:4 積分:1 註冊:2005-03-08 發送簡訊給我 |
請問一下,若將adoquery改為tclientdataset那要如何修改呢...因為我遇到的困難也是只有展一階的資料.. 而tclientdataset是接middle-tier的資料 ps.我是使用3-tier 架構去實作...先行謝過各位了
引言: Hi, 若是改為 ADO 的話, 寫法如下: 記得利用 TADOConnection 與資料庫建立連結.procedure TForm1.Button2Click(Sender: TObject); begin AddChildNode( nil, 0, 'root' ); end; function TForm1.AddChildNode(node: TTreeNode; typecode: integer; stype: string): TTreeNode; var Qry: ADOQuery; begin Result := TreeView1.Items.AddChild(node, stype); Qry:= ADOQuery.Create(self); Qry.Connection := ADOConnection1; Qry.Close; Qry.SQL.Clear; Qry.SQL.Text := 'SELECT * FROM MateType WHERE ParentCode = ' IntToStr(typecode); Qry.Open; While not Qry.Eof do begin AddChildNode(Result, Qry.FieldByName('typecode').AsInteger, Qry.FieldByName('type').AsString); Qry.Next; end; Qry.Free; end;其中的 紅色部分為修改為 ADO 的版本, 請再自行試試!! |
esp_pzj
初階會員 發表:32 回覆:70 積分:40 註冊:2007-02-09 發送簡訊給我 |
|
boss1215
一般會員 發表:6 回覆:10 積分:3 註冊:2009-03-09 發送簡訊給我 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |