如何在数据库中记录TREEVIEW的节点信息,400分大赠送,不是高手别看(300分)

  • 主题发起人 主题发起人 aaww
  • 开始时间 开始时间
A

aaww

Unregistered / Unconfirmed
GUEST, unregistred user!
我想在ACCESS数据库中记录TREEVIEW的节点结构
要求最佳方案
要求树型结构只有三层
公司名称-部门1
-部门2
-部门3-人员1
-人员2
随时可以添加删除节点,并立即更新到数据库中。
另外送100分
也可以用QQ:485557与我联系。
 
请搜索旧贴,有很多同类问题。
例如 http://211.101.4.25/delphibbs/dispq.asp?lid=611297
 
>树视图同数据库的关联

前 言

树形图用于显示按照树形结构进行组织的数据,其用途比较广泛,如计算机中的文件系统
(Windows95中的资源管理器)、企业或公司的组成结构等。VB、PB、Delphi等工具提供了
一个功能很强的树型控件TTreeView,可以用来描述复杂的层次关系。由于树形图结构较复杂,
使用起来常不知如何下手。笔者结合电信综合统计管理系统中指标维护这一具体实例,详细阐述
在Delphi下如何将树型控件的使用与数据库联系起来,实现数据分任意多层显示,方便地
进行增加、修改、删除操作,而且用拖放技术实现各层数据之间的移动、复制。

一、指标树的建立

具体方法是:创建一个数据库,设计指标表t_pub_index,包含index_id、parent_id、
index_name字段,其它字段根据实际业务而定,指标名称index_name将在树型控件的节点上显示,
index_id字段保存节点的唯一标识号,parent_id表示当前节点的父节点号,标识号组成了一个“链表”,
记录了树上节点的结构。设计一窗体Frm_sys_index,其上放置TreeView控件tv_zb、Query控件Query1
及其它指标属性编辑显示控件。一个树的节点又包含文本(Text)和数据(Data)。Text为String类,用来
显示指标或指标目录名称。Data则为无定形指针(Untyped Pointer),可以指向一个与节点相联系的数据结构,
该结构与数据库指标表相应域关联,如指标ID、上级节点ID。

Query控件的表达式为:

select index_id, parent_id, index_name from t_pub_index

start with index_id=0 connect by prior index_id=parent_id

其中start with 和connect by 是Oracle的SQL语句的保留字,使一条记录的parent_id列
的值等于前一记录的index_id列的值,并以parent_id等于0的记录开始。

建树的基本思路是:

procedure TFrm_sys_index.createtree;

var

curValue: indexPointer; //指向与节点相联系的数据结构的指针

curNode : TTreeNode; //当前节点

curid : integer; //当前节点标识号

begin

curNode := nil;

curid := -1;

Query_index.Open;

Query_index.first;

while not Query_index.Eof do

begin

new(curValue);

With curValue^ do

将数据库指标表t_pub_index各字段值赋curValue 所指数据结构

while(curid <> curValue.parent_id) do //当前节点的标识号不等于当前记录的父节点号

begin

curNode := curNode.parent;

curid:= indexPointer(curNode.data).index_id;

end;

curNode := tv_zb.Items.AddChildObject(curNode,

curValue^.index_name,curValue); //在当前节点上添加子节点,显示节点指标名称,
//所带指针指向一个与指标数据相联系的数据结构

curid := indexPointer(curNode.data).index_id;

Query_index.next;

end;

Query_index.close;

end;

二、增加、删除、修改树节点

单纯在Treeview 上增加、删除、修改节点只需用它本身提供的Treeview.Items. AddChildObject、
Treeview.Selected.Delete、Treeview.Selected.EditText等方法即可,但要相应修改
数据库中的数据,必须通过递归调用同一个函数(用于删除一个选项)来遍历所选节点下的所有子节点。
下面以删除节点为例介绍具体实现流程:

function TFrm_sys_index.delnode(node1:TTreenode):TTreenode;

var

childnode:TTreenode;

begin

childnode:=node1.GetLastChild; //按倒序获得子项,因为删除选项时,列表会发生变化

while childnode<>nil do

childnode:=delnode(childnode); //如子项不为空,进行递归调用

index_id:=inttostr(indexpointer(node1.data).index_id);//获得该节点对应指标

在数据库删除相应指标;

result:=node1.parent.GetPrevChild(node1); //定位到该节点的上一节点

node1.delete; //删除树节点

end;

三、拖动树节点

拖动树节点基本上是通过建立目标项的新子项、向它复制源项、删除原项来移动选项。
与上述删除操作相似,也是通过递归调用同一个函数(用于移动一个选项),
按倒序移动所选节点下的所有子节点。下面是递归过程的代码:

procedure TFrm_sys_index.CopyNodeUnder(treeview:TTreeview;

sourcenode,targetnode:ttreenode);

var

newnode:ttreenode;

i:integer;

begin

newnode:=treeview.items.addchildfirst(targetnode,''); //建立目标项

newnode.assign(sourcenode); //复制源项属性

for i:=sourcenode.count-1 downto 0 do //递归调用,按倒序移动其所有子项

CopyNodeUnder (treeview,sourcenode.item,newnode);

treeview.items.delete(sourcenode); //删除源项

end;

Treeview对拖动操作提供支持,我们将组件的DragKind属性设置为dkDrag,
DragMode属性设置为dmAutomatic,并为OnDragOver与OnDragDrop事件编写了处理程序。
OnDragOver事件处理程序对允许移动的条件进行判断,排除需要避免的特殊情况。代码如下:

procedure TFrm_sys_index.tv_zbDragOver(Sender, Source: TObject; X,

Y: Integer; State: TDragState; var Accept: Boolean);

var

targetnode,sourcenode:TTreenode;

begin

targetnode:=tv_zb.getnodeat(x,y);

if (Source=Sender) and (targetnode<>nil) then //保证移动在TreeView上,且目标节点不为空

begin

Accept:=true;

sourcenode:=tv_zb.selected;

//以下代码防止用户将一个选项拖到其子项上(它会随着选项一起移动,导致死循环)

while (targetnode.parent<>nil) and (targetnode <> sourcenode) do

targetnode:=targetnode.parent;

if (targetnode = sourcenode) then Accept:=false;

end

else Accept:=false;

end;

OnDragDrop事件处理程序启动前述移动过程CopyNodeUnder,修改数据库数据。
此外,在大批量添加数据到Treeview中时最好使用TreeView.Items.BeginUpdate和
TreeView.Items.EndUpdate,这样能加快显示速度。大致流程如下:

procedure TFrm_sys_index.tv_zbDragDrop(Sender, Source: TObject; X,

Y: Integer);

var

targetnode,sourcenode:TTreenode;

begin

targetnode:=tv_zb.getnodeat(x,y); //获得源节点

sourcenode:=tv_zb.selected; //获得目标节点

修改数据库中当前节点的父节点号parent_id,使其等目标节点标识号;

tv_zb.items.beginupdate; //禁用TreeView重绘操作

try

copynodeunder(tv_zb,sourcenode,targetnode); //启动移动过程

tv_zb.selected:=targetnode;

finally

tv_zb.items.endupdate; //重新设置

end;

end;
 
你确定只有三层的话,最好用三个表,如果只用一个表的话,里面的数据将会杂乱不堪。
》》随时可以添加删除节点,并立即更新到数据库中。
你先更新数据库,在更新TreeView,这样可以防止插数据库出错时出现树型列表与数据库
中内容不符合。
用以下方式记录应该比较好
type
TGS=record //公司
GSid:Integer;
GSname:String;
end;
PGS=^TGS; //公司指针

TBM=record //部门
BMid:Integer; //部门ID
GSid:Integer; //公司ID
BMname:String
end;
PBM=^TBM; //部门指针
TRY=record //人员
RYid:Integer //人员id
BMid:Integer //部门id
GSid:Integer //公司id
RYname:String
end;
PRY=^TRY; //人员指针
 
有两种方法:
其一用TreeView的SelectedIndex属性保存部门号等整型数据。
其二用指针保存TreeView.Selected.Data数据,该数据可是任意类型。
具体代码要的话可以贴出来,你真的要吗,不会是真的想要吧?
 
不行,我只能用一个表
 
就一个表照上面那样做也行,只是里面的数据肯定会比较混乱,
 
我代码自己写,只想知道原理,
KALS的看不懂,请具体说说
我赞同叶不归的,
现在可以肯定的是
用三个字段
node_id node_parent node_text
来记录树结构
但是我最想知道的是在添加或删除某一节点时,如何对数据库进行操作呢,即如何寻找该节点在数据库
中的位置,如何插入使操作时最安全,而且速度最快。
注意:实际上我只需要2级树就可以了,因为公司只有一个。
 
呵呵,要添加删除还不容易?
看一下这个:
当然你的库应该是有部门号(id)、上级部门号(tid)、部门名称(name)这三个字段吧!
// 增加部门:selectedindex就是tid,
SQL: insert ...(id,tid) values(maxid+1,selectedindex)
// 删除部门:selectedindex就是id
SQL: delete ... where id = selectedindex
当然,操作完刷新一下,树的形成是一个递归来完成的....
还有增加就是插入。
 
你用的表不会只有一个吧,都在一个表里岂不太浪费空间了?
 
“不是高手别看”

什么呀?
我不是高手我也会,有什么了起,不准看?[:D]
 
有没有人为我的要求量身定做一个,或者我把辕马发过去,帮我改完啊
 
从数据结构上来说有很多方案,具体选那个,得看你的需求了。
1、id , parent_id 结构
2、id, childNode , bortherNode
3、id, parent id list (比如:1,4,3344,888888)
4、id, level, order

大致就这么些了,各有各的用处,第一个利于移动节点,第二各利于排序,第三个速度快
第四个层次清楚。
 
soul有方式和你联系吗,我的QQ是485557
 
用递归就行了,我做过,爽的很,可以无穷级增加和删除
 
如果用递归,可以采用soul的第一种方案
很好
 
aaww,问题可以结束了吧?
 
卷起千堆雪tyn,你那来的这么多文档.[:)]
 
还不能结束啊,没有一个让我满意的啊
 
多人接受答案了。
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
D
回复
0
查看
1K
DelphiTeacher的专栏
D
后退
顶部