有关treeview和数据库关联的几个问题?

thomsonyin 2003-08-13 04:53:25
各位前辈:
我想在一个窗体上左边放一个treeview,右边放一个dbgrid.右边进行增加,修改和删除工作,数据库结构是:id,parentid,name
我想问几个思路性的问题:
1,点击左边treeview的节点,右边显出它的兄弟好呢?还是儿子好?
2,右边增加一个记录后,也就是进数据库后,是否需要重新生成左边的树?
3,从数据库中读数据生成一棵树,采用什么方法好呢?
请大家指点。有代码最好不过,谢谢!
...全文
137 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
WuLoveXue 2003-08-20
  • 打赏
  • 举报
回复
老王的是可以的,别人的我不就不知道了!你说说看你那边出什么错?
WuLoveXue 2003-08-19
  • 打赏
  • 举报
回复
IORILI(近视眼@_@) 你的办法里每个节点只能有一个值,比如:我要显示的值是STR,我要写到数据库的是ID,你的这种办法就取不出来ID了,老王写进去的是一个RECORD,所以很关联记录到节点上!所以.............嘿嘿!
IORILI 2003-08-19
  • 打赏
  • 举报
回复
1,点击左边treeview的节点,右边显出它的兄弟好呢?还是儿子好?

*我觉得应该显示treeview的同级items,就像windows的资源管理起那样不是更好吗?????

2,右边增加一个记录后,也就是进数据库后,是否需要重新生成左边的树?
*因该是不需要的。

3,从数据库中读数据生成一棵树,采用什么方法好呢?
请大家指点。有代码最好不过,谢谢!
上面wdsimon(老王) 仁兄的方法没试过,不过我觉得代码量太多,还有递归!,下面的代码大家觉得如何??:
procedure Tcpya_app.FormCreate(Sender: TObject);//窗体初始化时,加载树。
begin
datamodule2.tree.close; //tree:是数据模块中的adoquery
datamodule2.tree.sql.clear;
datamodule2.tree.sql.add('select name from plat order by name');//按照name排序。
datamodule2.tree.Active:=true;
datamodule2.tree.Open;
while not datamodule2.tree.Eof do//填充树
begin
with tv.Items do//增加节点
begin
MyTreeNode1 := Add(nil,trim(datamodule2.tree.fields[0].asstring));//自动增加父节点
with datamodule2 do
begin
child.close;//child是数据模块中的adoquery
child.SQL.Clear;
child.SQL.Add('select comp from dalei where plat='''+Trim(datamodule2.tree.Fields[0].asstring)+''''+' order by comp');
child.Active:=true;
child.Open;
While Not child.Eof do
begin
TV.Items.AddChild(mytreenode1,trim(child.Fields[0].AsString));//在父节点下加子节点
child.Next;
end; end;
datamodule2.tree.Next;
end;
end;
end;
上面的程序中生成父节点的表可以说是主表吧,声称子节点的表是从表,
其中两个表通过plat字段相关联,
WuLoveXue 2003-08-19
  • 打赏
  • 举报
回复
老王,我想问下你这种办法,在C++builder里怎么实现Record类型?
还有这种记录类型你是怎么读出数据的?
wdsimon 2003-08-19
  • 打赏
  • 举报
回复
MD003就是你表里的parentid(父节点),MD006 就是你表里id(当前节点),BOMMD 就是你的表
需要注意
1、首先,在单元接口部分声明一记录类型及其指针,用来保存你的树节点需传递的信息。
type
pchar=^str;
str=record
tcaption:string;
num:integer;
end;
当然你,可以依据你的需要来做(如节点不需保存信息,也可不要指标)。

2、写一生成树的函数,注意递归:
function TForm1.ShowTree(TNode: TTreeNode; s: string): boolean;
var
QR:TADOQuery;
TmpNode:TTreeNode;
p:pchar;
begin
QR:=TADOQuery.Create(self);
if TNode=nil then //判断是否顶层接点 ;
begin
new(p);
p^.tcaption:=s;
p^.num:=1;
TNode:=Treeview1.Items.AddChildObject(TNode,p^.tcaption,p);
end;
with QR,treeview1 do
begin
close;
connection:=ADOCONNECTION1;
SQL.Clear;
SQL.Add('select parentid,id from 你的表 where condition');
//注意,condition中你可带参数,也可不带参数
parameters[0].Value:=s;//那么这句可要也可不要;
open;
ACTIVE;
first;
while not eof do
begin
new(p);
p^.tcaption:=QR.fieldbyname('parentid').AsString;
P^.num:=QR.fieldbyname('id').AsInteger;
TmpNode:=Items.AddChildObject(TNode,p^.tcaption,p);
ShowTree(TmpNode,p.tcaption);//递归
next;
end;
end;
end;


thomsonyin 2003-08-19
  • 打赏
  • 举报
回复
这个树形太难了,我试了老王的不行,别人的也不行,,没有一个成功的
不知道为什么?
下面一个也不行:
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, DB, ADODB, ComCtrls;

type
TForm1 = class(TForm)
TreeView1: TTreeView;
ADOConnection1: TADOConnection;
ADOQuery1: TADOQuery;
procedure FormCreate(Sender: TObject);
private
function FindParent(ID:String):TTreeNode;
procedure CreateTree;
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
stlID:TStringList ;
implementation

{$R *.dfm}
function Tform1.FindParent(ID:String):TTreeNode;
var
i:Integer;
begin
result:=nil;
for i:=TreeView1.Items.Count-1 downto 0 do
if stlID.Strings[i]=ID then
begin
result:=TreeView1.Items[i];
break;
end;
end;

procedure Tform1.CreateTree;
var
tmpNode:TTreeNode;
begin
adoQuery1.SQL.Text:='select * from material order by ParentID';
adoQuery1.Open;
adoQuery1.First;
while not adoQuery1.Eof do
begin
tmpNode:=TreeView1.Items.AddChild(FindParent(adoQuery1.FieldByName('ParentID').AsString),adoQuery1.FieldByName('Name').AsString);
stlID.Add(adoQuery1.FieldByName('ID').AsString);//记录ID
adoQuery1.Next;
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
createtree;
end;

end.
thomsonyin 2003-08-19
  • 打赏
  • 举报
回复
老王:你好!
我的Id,parentId都是字符串,并不是整数。
WuLoveXue 2003-08-19
  • 打赏
  • 举报
回复
TO 爱死你:我个人看法,觉得这个和递归应该没关系无所谓!不用递归,其实算法也是和递归一样的啊!只是表现形式不同!
WuLoveXue 2003-08-19
  • 打赏
  • 举报
回复
to 老王:你创建了这么多AdoQuery,不用释放吗?
thomsonyin 2003-08-19
  • 打赏
  • 举报
回复
好象有许多朋友对生成树用递归有保留看法
目前生成树确实有递归及非递归两种
我想问一问哪个好?
他们说用递归三层以上特慢,
是不是?
老王你的意见呢?
wdsimon 2003-08-19
  • 打赏
  • 举报
回复
WuLoveXue(晕死,又这样) :C++builder我不会,delphi也初学。
treeview的节点有一个data的指针属性,利用他可以把节点存储的信息读出来,
以下代码是递归删除选定节点下所有节点(包含子节点的节点,同时删除数据库数据):
注意:pchar在展开树节点时已申明。
procedure TForm1.detree(node: ttreenode);
var
tnode:ttreenode;
i:integer;
s1,s2:string;
begin
if node.HasChildren then
begin
for i:=node.Count-1 downto 0 do
begin
if node.Item[i].HasChildren then
detree(node.Item[i]);
s1:=pchar(node.Item[i].Data)^.mcaption;
s2:=pchar(node.Item[i].data)^.tcaption;
with form1.pub do
begin
close;
sql.Clear;
sql.Add('delete BOMMD where MD001=:AA and MD003=:BB');
parameters[0].Value:=s1;
parameters[1].Value:=s2;
ExecSQL;
end;
node.Item[i].Delete;
end;
end;
node.Delete;
end;
thomsonyin 2003-08-18
  • 打赏
  • 举报
回复
老王:你好!
你的'select MD003,MD006 from BOMMD where MD001=:NN');‘
md003
md006
等是什么东东?我有点看不懂。
Little2000 2003-08-14
  • 打赏
  • 举报
回复
1、显示儿子会更好一点;
2、不需要重新生成树,只需要再增加一个节点就可以了;
3、给你一个简单的例子看看:
var
FirstNode,SecondNode: TTreeNode;


TreeView1.Items.Clear;
FirstNode := TreeView1.Items.AddFirst(TreeView1.Items.GetFirstNode, '系统角色');
AdoRole.Close;
AdoRole.SQL.Text := 'select * from RoleTable';
AdoRole.Open;
if AdoRole.RecordCount > 0 then
begin
AdoRole.First;
while not AdoRole.Eof do
begin
SecondNode := TreeView1.Items.AddChild(FirstNode, AdoRole.FieldByName('RoleName').AsString);
AdoUser.Close;
AdoUser.SQL.Text := 'select * from UserList where RoleID = '+AdoRole.FieldByName('RoleID').AsString+'';
AdoUser.Open;
while not AdoUser.Eof do
begin
TreeView1.Items.AddChild(SecondNode, AdoUser.FieldByName('Name').AsString);
AdoUser.Next;
end;
AdoRole.Next;
end;
end;
zhoutian618 2003-08-14
  • 打赏
  • 举报
回复
不好意思,楼主,我来看得太迟了,因为我的网络有点小问题。

我常用的方法是78(编程失败,自己.人生辉煌,别人) 的方法。
代码可以参照wdsimon(老王)的。

建议你自己多写一点处理各种问题类,
建议你用类来封装,
尽量少用结构或指向结构的指针,建议底层的数据结构用类来封装,这样可扩展性会更好。
thomsonyin 2003-08-13
  • 打赏
  • 举报
回复
我的e-mial是:delphifly@tom.com
michaelpeng7799 2003-08-13
  • 打赏
  • 举报
回复
复录结构用递归,一般可能还不用,如果是左边树中显示库中的表和一的字段,右边显示左边所选表的记录,那用循环就可以了,最多是多重的。

另外试试第3方控件,比如devexpress的那个dbtreelist什么的。
Spqk005 2003-08-13
  • 打赏
  • 举报
回复
1\当然是生成儿子好啊
2\不要了直接用语句加个ITEM就可以了
3\要程序留个MAIL给
thomsonyin 2003-08-13
  • 打赏
  • 举报
回复
谢谢老王,让我试一试,
wdsimon 2003-08-13
  • 打赏
  • 举报
回复
3、用递归:
首先,在单元接口部分声明一记录类型及其指针,用来保存你的树节点需传递的信息。
type
pchar=^str;
str=record
tcaption:string;
num:integer;
end;
写一生成树的函数,注意递归:
function TForm1.ShowTree(TNode: TTreeNode; s: string): boolean;
var
QR:TADOQuery;
TmpNode:TTreeNode;
p:pchar;
begin
QR:=TADOQuery.Create(self);
if TNode=nil then //判断是否顶层接点 ;
begin
new(p);
p^.tcaption:=s;
p^.num:=1;
TNode:=Treeview1.Items.AddChildObject(TNode,p^.tcaption,p);
end;
with QR,treeview1 do
begin
close;
connection:=ADOCONNECTION1;
SQL.Clear;
SQL.Add('select MD003,MD006 from BOMMD where MD001=:NN');
parameters[0].Value:=s;
open;
ACTIVE;
first;
while not eof do
begin
new(p);
p^.tcaption:=QR.fieldbyname('MD003').AsString;
P^.num:=QR.fieldbyname('MD006').AsInteger;
TmpNode:=Items.AddChildObject(TNode,p^.tcaption,p);
ShowTree(TmpNode,p.tcaption);//递归
next;
end;
end;
end;
然后在需要的时候调用该函数就可以了,例如:
procedure TForm1.FormCreate(Sender: TObject);
begin
ShowTree(nil,'0102-73316000');
end;
上述为一展BOM树的实例(BOM结构以关系数据库结构存储)。
2、不需重新生成树,直接调用
treeview1.items.addchildobject()即可增加子节点
1、右边显示儿子好。
thomsonyin 2003-08-13
  • 打赏
  • 举报
回复
能否详细一点?
加载更多回复(2)

5,388

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧