首页 > 数据库 > 数据库开发技术 > 关于TreeView控件结合数据库的使用
老天阿,我写了一中午,发表的时候竟然出错了,白干了 ,气死我了
//在这里先说明一下结点数据是如何在结点中存储的。我们知道TTreeNode有两个属性:TreeNode.Text 和
TreeNode.data。TreeNode.Text 是结点的显示文本,在这里它的值是ParaValue;TreeNode.Data是一个指针,可以指向变量也可以指向对象,
这这里它指向的是一个变量,变量的值是ParaCode;
下面先看一组函数;
//插入树中新结点
function InsertNode(ParentNode:TTreeNode;NodeScript:string;SubNodeCode:string=''):TTreeNode;
var
vNodeScript,vNodeCode:string;
pStr:^String;
begin
Result:=nil ;
vNodeScript:=NodeScript;
VNodeScript:=StringReplace(NodeScript,' ','',[rfReplaceAll]); //消除空格,防止歧义
VNodeScript:=StringReplace(NodeScript,' ','',[rfReplaceAll]);
if vNodeScript='' then
Raise Exception.Create('节点描述不能为空!');
if vNodeScript='其它' then
vNodeScript:='其他';
if FindNode(ParentNode,vNodeScript) <>nil then
Raise Exception.Create('该层中已存在相同名称的子节点!');
if vNodeScript='其他' then
begin
if ParentNode = nil then
begin
vNodeCode:='999' //默认值
end
else
begin
new(pStr);
pStr:=ParentNode.Data;
vNodeCode:=pStr^+'999'; //默认值
end;
end
else
begin
if (SubNodeCode <> '') then
begin
if (SubNodeCode<='000') or (SubNodeCode>'999') then //检查编码的合法性
Raise Exception.Create('编码错误!');
new(pStr);
if ParentNode<>nil then
pStr:=ParentNode.Data ;
vNodeCode:=pStr^+SubNodeCode;
end
else
begin
vNodeCode:=NewCode(ParentNode); //生成新编码
end;
end;
if (LocatNode(vNodeCode)<>nil) then //检查编码是否已存在
Raise Exception.Create('编码已存在!');
new(pStr);
pStr^:=vNodeCode;
Result := Tree.Items.AddChildObject(ParentNode,vNodeScript,pStr);
end;
// 查找指定名称的子结点
Function FindNode(ParentNode:TTreeNode;NodeScript:string):TTreeNode;
var
Node:TTreeNode;
begin
result:=nil;
if ParentNode =nil then
Node := Tree.Items.GetFirstNode
else
Node:=ParentNode.getFirstChild;
while Node <> nil do
begin
if Node.Text = NodeScript then
begin
Result:=Node;
break;
end;
Node:=Node.getNextSibling;
end;
end;
//生成新编码
Function NewCode(ParentNode:TTreeNode):string;
var
MaxNodeCode,SubCode:String;
begin
MaxNodeCode:=GetMaxNodeCode(ParentNode); //取最大节点编码
SubCode:=copy(MaxNodeCode,length(MaxNodeCode)-2,3);
SubCode:=inttostr(strtoint(SubCode)+1);
while length(SubCode)<3 do
SubCode:='0'+SubCode;
result:=copy(MaxNodeCode,1,length(MaxNodeCode)-3)+SubCode;
end;
//取最大节点编码
Function GetMaxNodeCode(ParentNode:TTreeNode):string;
var
Node:TTreeNode;
pStr:^string;
begin
new(pStr);
if Tree.Items.Count = 0 then //空树
begin
Result:='000';
exit;
end;
if parentnode=nil then //根节点
begin
Node := Tree.Items.GetFirstNode;
end
else
begin
Node:=ParentNode.GetFirstChild;
if (Node = nil) then //节点存在但无子节点
begin
pStr:=ParentNode.Data;
result:=pStr^+'000';
exit;
end;
end;
//正常情况下
pStr:=Node.Data;
if Node.Text <> '其他' then //'其他'节点自动略过
result:=pStr^;
while Node.getNextSibling <>nil do //遍历树取最大编码 (除去‘其他’节点)
begin
pStr:=Node.getNextSibling.Data;
if Node.getNextSibling.Text = '其他' then
begin
Node:=Node.getNextSibling;
Continue;
end;
if result
Node:=Node.getNextSibling;
end;
end;
//向数据库中保存数据的存储过程
create procedure I_SysParameter @ParaCode varchar(30),@ParaValue varchar(100)
as
begin
if LTrim(RTrim(@ParaCode)) = ''
begin
Raiserror('错误:参数代码为空!',16,1)
Return
end
if LTrim(RTrim(@ParaValue)) = ''
begin
Raiserror('错误:参数值为空!',16,1)
Return
end
insert T_SysPara (ParaCode,ParaValue) values (@ParaCode,@ParaValue)
--select 'ok' operation
end
//程序调用代码
//添加根结点
procedure TSysParameterForm.BitBtn1Click(Sender: TObject);
var
TreeNode:TTreeNode;
p:^string;
DefaultCursor:TCursor;
begin
inherited;
Edit1.SetFocus;
Edit1.SelectAll;
if trim(Edit1.Text )='' then
begin
application.MessageBox('根结点名称为空,不能添加!',MsgCaption,mb_ok+mb_IconError);
exit;
end;
DefaultCursor :=Screen.Cursor ;
Screen.Cursor :=crHourGlass;
try
TreeNode:=ParTree.InsertNode(nil,trim(Edit1.Text)); //生成新结点
p:=TreeNode.Data;
setlength(Parameters,2) ; //Parameters是TWidestringDYNArray类型的数组
Parameters[0]:=p^ ;
Parameters[1]:=TreeNode.Text ;
dm.CallOperation2(5010,Parameters); //这是我的一个三层调用,调用它的最终结果是执行存储过程I_SysParameter,把数据保存到数
据库中,大家只要知道它的调用结果就可以了,对于函数本身可以不去关心。
except
on e:Exception do
begin
Screen.Cursor := DefaultCursor;
application.MessageBox(pchar(e.Message ),MsgCaption,mb_ok+mb_IconError);
exit;
end;
end;
Screen.Cursor := DefaultCursor;
end;
//添加子结点
procedure TSysParameterForm.BitBtn2Click(Sender: TObject);
var
TreeNode:TTreeNode;
p:^string;
DefaultCursor:TCursor;
begin
inherited;
Edit2.SetFocus;
Edit2.SelectAll;
if trim(Edit2.Text )='' then
begin
application.MessageBox('结点名称为空,不能添加!',MsgCaption,mb_ok+mb_IconInformation);
exit;
end;
if ParTree.Selected = nil then
begin
application.MessageBox('请选择父节点!',MsgCaption,mb_ok+mb_IconInformation);
exit;
end;
DefaultCursor :=Screen.Cursor ;
Screen.Cursor :=crHourGlass;
try
TreeNode:=ParTree.InsertNode(ParTree.Selected,trim(Edit2.Text));
p:=TreeNode.Data;
setlength(Parameters,2) ;
Parameters[0]:=p^ ;
Parameters[1]:=TreeNode.Text ;
dm.CallOperation2(5010,Parameters);
except
on e:Exception do
begin
Screen.Cursor := DefaultCursor;
application.MessageBox(pchar(e.Message ),MsgCaption,mb_ok+mb_IconError);
exit;
end;
end;
Screen.Cursor := DefaultCursor;
end;
//以上两个操作差别不大,在我的程序中是分开执行的,懒的修改,全部贴出了。
以上是树新结点的添加操作,代码是我从程序中复制的,有一些删改,如有错误指出后我将修改,明天如果有时间完成结点的修改删除
结点修改
声明一个全局变量
var
NodeText:string;
在树的Editing和Edited事件中
procedure TSysParameterForm.TreeView1Editing(Sender: TObject; Node: TTreeNode; var AllowEdit: Boolean);
begin
NodeText:=node.Text;
end;
procedure TSysParameterForm.TreeView1Edited(Sender: TObject; Node: TTreeNode; var S: String);
var
p:^string;
DefaultCursor:TCursor;
begin
if length(trim(s))=0 then
begin
application.MessageBox ('参数值不能为空',MsgCaption,mb_ok+mb_IconError);
application.ProcessMessages;
Node.Text := NodeText;
end
else
begin
DefaultCursor :=Screen.Cursor ;
Screen.Cursor :=crHourGlass;
try
//修改数据库中的数据
p:=Node.Data;
setlength(Parameters,2) ;
Parameters[0]:=p^ ;
Parameters[1]:=s ;
dm.CallOperation2(5011,Parameters); //三层调用
except
on e:Exception do
begin
Screen.Cursor := DefaultCursor;
application.MessageBox(pchar(e.Message ),MsgCaption,mb_ok+mb_IconError);
Node.Text := NodeText; //如果错误,恢复原值
exit;
end;
end;
Screen.Cursor := DefaultCursor;
end;
end;
//修改操作调用的存储过程
create procedure U_SysParameter @ParaCode varchar(600),@ParaVarlue varchar(50)
as
update T_SysPara set ParaValue = @ParaVarlue where ParaCode = @ParaCode
select 'ok' operation
//删除操作
procedure TSysParameterForm.N1Click(Sender: TObject);
var
p:^string;
begin
inherited;
if ParTree.Selected = nil then exit;
if Application.MessageBox(IsDelData,MsgCaption,mb_yesno+mb_IconQuestion) = idno then exit;
p:=ParTree.Selected.Data;
ParTree.Items.Delete(ParTree.Selected); //删除结点
try
SetLength(Parameters,1);
Parameters[0]:=p^;
dm.CallOperation2(5012,Parameters); //三层调用,删除数据库中的数据
except
on e:exception do
begin
application.MessageBox(pchar(e.Message),MsgCaption,mb_ok+mb_ICONError);
exit;
end;
end;
end;
//删除结点的存储过程
Create Procedure D_SysParameter @ParCode varchar(600)
as
Delete T_SysPara where ParaCode like @ParaCode+'%' --包括所有子结点
Select 'ok' operation
//以上基本完成了树的添加、修改、删除登记本操作,下面讲述一下数结点的多选,
树结点的多选应用的比较多,用起来也比较灵活。一个树结点共有三种状态:未选择,全选择和部分选择。未选择:本结点以及本结点的所有子结点都处于未选择状态;全选择:本结点以及本结点的所有子结点都处于选择状态;部分选择:本结点一部分子结点处于未选择状态。结点可以通过它的stateImages和stateIndex属性以图片变换的方式来表示这三种状态,当一个接点的状态发生变化时这个结点的所有父结点和所有子结点的状态都有可能发生变化。先看两个状态同步函数:
//改变所有子结点的状态
Procedure TSysParameterForm.ChangeNodeChild(Node:TTreeNode;StIndex:integer);
var
i:integer;
begin
For i:=0 to Node.Count-1 do
begin
Node.Item[i].StateIndex:=StIndex; //
if Node.Item[i].Count>0 then
ChangeNodeChild(Node.Item[i],StIndex); //递归
end;
end;
//改变所有父结点的状态
Procedure TSysParameterForm.ChangeNodeParent(TreeView:TTreeView;Node:TTreeNode;StIndex:integer);
var
i,j:integer;
isAll,isChecked:Boolean;
ParentNode:TTreeNode;
begin
isAll:=True;
isChecked:=False;
For i:=0 to TreeView.Items.Count-1 do
begin
if TreeView.Items.Item[i] = Node then
begin
ParentNode:=TreeView.Items.Item[i].Parent;
if ParentNode<>nil then
begin
if ((ParentNode.StateIndex<>2) and (ParentNode.StateIndex<>3))
and (StIndex<>2) then Break; //父节点未被选中 且选中节点被取消选则 跳出
For j:=0 to ParentNode.Count-1 do //判断状态
begin
if (parentNode.Item[j].StateIndex=1) or (parentNode.Item[j].StateIndex=3) then
isAll:=False;
if (ParentNode.Item[j].StateIndex=2) or (parentNode.Item[j].StateIndex=3) then
isChecked:=True;
end; //For j:=0 to ParentNode.Count-1 do
if isAll then
parentNode.StateIndex:=2
else begin
if isChecked then
ParentNode.StateIndex:=3
else
ParentNode.StateIndex:=1;
end;
ChangeNodeParent(TreeView,parentNode,StIndex); //递归
end; //if ParentNode<>nil then
end; //if TreeView.Items.Item[i] = Node then
end; //For i:=0 to TreeView.Items.Count-1 do
end;
//在点击TreeView时
procedure TSysParameterForm.TreeView1MouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
MyHitTest : THitTests;
node: TTreeNode;
begin
node := TreeView1.GetNodeAt(x,y); //被点击的节点
MyHitTest := TreeView1.GetHitTestInfoAt(X,Y); //点击点
if htOnStateIcon in MyHitTest then //是否在图标位置
begin
//修改树的状态
if node.StateIndex = 2 then
begin
node.StateIndex := 1;
NodeChild(Node,1);
NodeParent(TreeView1,Node,1);
end
else begin
node.StateIndex := 2;
NodeChild(Node,2);
NodeParent(TreeView1,Node,2);
end;
end;
end;
//这样在点击树结点图标的时候相关结点的状态将联动
//多选的一个应用,根据选结果生成sql语句的条件
Function TSysParameterForm.TreeValue(Node:TTreeNode):string;
var
i:integer;
Sql:String;
P:^String;
begin
if Node.StateIndex = 2 then
begin
p:=Node.Data;
if Node.Count>0 then
Sql:=Sql+' Or ParaCode like '''+P^+'%'''
else
Sql:=Sql+' Or ParaCode='''+P^+'''';
end
else if Node.StateIndex=3 then
Sql:=Sql+ TreeValue(Node.GetNext); //递归
Result:=Sql;
end;
//总算把要写的东西写完了,感觉写的比较乱,大家凑合着看吧。马上春节了,祝大家春节快乐,明年多挣钱!!!
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/8683736/viewspace-906423/ ,如需转载,请注明出处,否则将追究法律责任。