看看Visual Foxpro的solution ActiveX控件示例。
解决方案 »
- 个人发展 求高手指点
- 这个功能是怎么实现的?
- 尺码横向排列问题?
- 恭喜小CC新婚(破例穿马甲发帖)
- 用SQL 语句在ACCESS中,怎么样把字符型转换业数值型?兄弟们帮帮我!
- 请问我把DBGrid中的某一列变为下拉框后,如何用键盘操作???
- ★★★Oracle BLOB字段的读问题★★★
- [求助]d7从主程序无法进入bpl函数或用鼠标看bpl数据连接的值
- QuickReport设置了自定义大小的纸张格式,打印机里也设置乐自定义格式,为什么打印机走纸一直按A4的走?
- 在table中有cachedupdates可实现用applyupdate最后统一作保存。但好像adotable中没有这项属性了,请问大哥们在ADO中怎样才可以实现相同的功能
- 那位会根据计算机名算出IP(注意:运行程序的计算机与所求计算机的域名服务器不是一台)!
- help!!!!!!!
VB可以很方便地实现,它的集合有字符串型的关键字。这是多么重要的一个功能。
先给treeview1.items[n].data:=pointer(唯一的标记:integer)
当然需要用到一个链表
它用来保存标题信息的
然后存为文件
数据库中记录内容
使用唯一的标记同树相对应下回装入时只须装入树结构恢复以前的唯一标记
只有点击树叶时才利用标记查找相应的内容可能叙述不太清楚,我有源程要的话Mailto:[email protected]
setlength(node,imax);select level.....
open;ttreeview.items.clear;
node[0] := ttreeview.getfirstnode;while not eof do begin
i := fieldbyname('level').asinteger;
node[i] := ttreeview.items.add(node[i-1],[...id+mingcheng...]);
next;
end;good luck
1.在FormShow事件中,添加上级id=null的节点.
2.在TreeView1Expanding事件中,根据所选取得node判断是否有children,如果就动态添加好了。(注:这种方法的效率较高,尤其在树结构较为复杂的情形)。
有问题:[email protected]
这是一种比较简洁有效的表结构,哪里不正确,我都用了几年了。
所谓递归算法是否指在哪里?SQL中还是Treeview中?cszhz(丑小鸭):
数据量很大时肯定应该用你说的方法,而且这是一个很好的方法,实现起来也很简单。
但数据量较小时就需要一次性全部显示出来。对这个问题,基于Oracle,我想出来了一个比较好的解决办法:
将SQL语句改为:
Select A.ID,A.名称,A.idx,B.idx As ParentIdx,A.级数
From (Select Rownum As Idx,Level As 级数,ID,上级ID,名称
From 材料表
Start With 上级ID Is Null Connect By Prior ID=上级ID) A,
(Select Rownum As Idx,ID
From 材料表
Start With 上级ID Is Null Connect By Prior ID=上级ID) B
Where A.上级ID=B.ID(+)
Order By A.idx
这样将ID及上级ID组织成对应的Index及ParentIndex,在Treeview中依顺序Add,并可以直接通过Index获得其父结点作为Add的参数。当数据量不大时(千条记录级),这个办法很好,查询速度基本不受影响,而且一次循环就完成了树形显示。但数据量大了可能SQL就有点慢。对于SQLServer及其它数据库,级数(Level)虚列可以用数据结构实现,但Rownum列就不支持了,因此还得用其它办法。就是上面各位所说的递归,我还没弄明白?
你的代码什么意思,我看不大懂,可以指点一下吗(不是指语法)?比某个结点小一级的结点不一定就是它的父结点呀?
可以说说你的递归方法吗?
Start With 上级ID is NULL Connect by ID=上级ID”是按深度优先的,你可以浏览数据中的LEVEL的顺序,没有问题的具体可找一篇关于财务分级编码处理的一篇文章,我就不多说了,可以在计算机世界网找找
http://www.computerworld.com.cn/search/theme/themefile.asp?ThemeID=323
private
fTable:TDataSet;
fId,fParentId,fName:string;
function AddItem(var ParentIDList:TStringList):TTreeNode;
procedure GetInitParentID(var parentIdList:TStringList);
public
function GetId:integer;
procedure BuildTree;
procedure ClearTree;
function FindItem(Id:integer):TTreeNode;
function SelectItem(Id:integer):TTreeNode;
published
property FieldID:string Read fID Write fID;
property FieldParentID:string Read fParentId Write fParentId;
property FieldName:string Read fName Write fName;
property DataSource:TDataSet Read fTable Write fTable;
property ActiveId:integer Read GetId;
end;procedure Register;implementationfunction TDBTreeView.FindItem(Id:integer):TTreeNode;
var
i:integer;
begin
Result:=nil;
For i:=0 to Items.Count-1 do
begin
if integer(Items[i].Data) = Id then
begin
Result:=Items[i];
Exit;
end;
end;
end;function TDBTreeView.GetId:integer;
begin
If Selected=nil then Result:= -1
else Result:=integer(Selected.Data);
end;procedure TDBTreeView.GetInitParentID(var parentIdList:TStringList);
var
childIdList:TStringList;
i:integer;
begin
childIDList := TStringList.Create;
try
parentIDList.Clear;fTable.Filtered := false;
fTable.First;While not fTable.Eof do
begin
parentIdList.add(fTable.FieldByName(fParentId).AsString);if fTable.FieldByName(fParentId).AsString <> fTable.FieldByName(fId).AsString then
childIdList.add(fTable.FieldByName(fId).AsString);fTable.next;
end;for i := parentIdList.Count - 1 downto 0 do
begin
if childIdList.IndexOf(parentIdList[i]) <> -1 then
parentIdList.Delete(i);
end;finally
childIdList.Free;
end;
end;function TDBTreeView.AddItem(var ParentIDList:TStringList):TTreeNode;
var
CurrentItem:TTreeNode;
Name:string;
CurId:integer;
begin
CurrentItem:=FindItem(fTable.FieldByName(fId).AsInteger);//已经安装
If CurrentItem <> nil then
begin
Result := nil;
Exit;
end;//父节点还未安装
if ParentIdList.Indexof(fTable.FieldByName(fParentID).AsString) = -1 then
begin
Result := nil;
exit;
end;Name:=fTable.FieldByName(fName).AsString;
CurId :=fTable.FieldByName(fID).Asinteger;//找到父节点,装在父节点下面
CurrentItem := FindItem(fTable.FieldByName(fParentID).Asinteger);
Result:=Items.AddChildObject(CurrentItem, Name, Pointer(CurID));ParentIdList.Add(IntToStr(CurID));
end;procedure TDBTreeView.BuildTree;
var
ChangeEvent:TTVChangedEvent;
initParentIdList:TStringList;
HasChanged:boolean;
begin
If (fTable=nil) or (not fTable.Active) then Exit;
ChangeEvent:=OnChange;
OnChange:=nil;
Items.BeginUpdate;
try
initParentIdList := TStringList.Create;
try
GetInitParentID(initParentIdList);
ClearTree;
HasChanged := true;while HasChanged do
begin
HasChanged := false;
fTable.Filtered := false;
fTable.First;
While not fTable.Eof do
begin
if AddItem(initParentIdList) <> nil then
HasChanged := true;
fTable.Next;
end;
end;
finally
initParentIdList.Free;
end;
finally
Items.EndUpdate;
OnChange:=ChangeEvent;
end;
end;procedure TDBTreeView.ClearTree;
begin
Items.BeginUpdate;
While Items.Count>0 do Items.Delete(Items[0]);
Items.EndUpdate;
end;procedure Register;
begin
RegisterComponents('QuickMail',[TDBTreeView]);
end;function TDBTreeView.SelectItem(Id: integer): TTreeNode;
var
aNode:TTreeNode;
begin
result := FindItem(Id);
if result = nil then exit;
aNode := result.parent;
while aNode <> nil do
begin
aNode.Expand(false);
aNode := aNode.Parent;
end;
result.Selected := true;
end;end.
我刚刚做了财务软件的科目的ttreeview 结构
刚开始我也用了递归啊什么的算法
实际上,根本就很简单
只要建立一个代码字段(字符串),并且排序
把字段读出来就可以了!
如:
100
100001
100002
100002001
读出字段后
判断字段的长度是3就是一级节点,是六就是二级。
呵呵,只要读一次数据库就可以了
只要在TreeView的OnExpanding中去产生下一级的子结点就行了,还有在使用的过程中多注意一下TreeView的AddChildObject()中Data属性的用法,用好指针问题就解决了。
你的代码是用循环查找,没有意思。ffossil(吴下阿蒙),lengxue(冷血),hwy():
我也有点笨,你们的方法我还是不明白。结点的深度不一定是一直增加的,并且Level属性是只读的。
比如前面的给出的数据,当我加到"LED显示器"或"刻录光驱"时,用TTreeView.Items.AddChild(Node,'XXXX'),其中Node参数如何确定?
只不过是ORACLE内部处理不用你操心而已(ORACLE 毕竟一分价钱一分货,呵呵)
其实最好设置LEVEL字段,可以减轻数据库负荷、更换数据库也方便一点“TTreeView.Items.AddChild(Node,'XXXX')” 看我伪代码啊
数据定位:用SEELECTED属性啊,然后从TEXT中分离出ID1,读出PARENTID1
同级增加 PARENTID.NEW =PARENTID1
子级增加 PARENTID.NEW =ID1 就这样了,如果还有问题在大富翁找我的联系方法 --- fossil
我还是看不懂也。
当然这里根本不用考虑数据分级的问题,问题是现在已经有了分级的数据,如何一次循环直接就增加到TTreeView上。假设Item.Text:=<名称>;Item.Data:=<ID>.
你不要写伪码,按Pascal写一个好吗?
Parent Child ---------------------------------- ----------------------------------World Europe World North America Europe France France Paris North America United States North America Canada United States New York United States Washington New York New York City Washington Redmond This example is easier to interpret:World North America Canada United States Washington Redmond New York New York City Europe France Paris
--存储过程
CREATE PROCEDURE expand (@current char(20)) asSET NOCOUNT ONDECLARE @level int, @line char(20)CREATE TABLE #stack (item char(20), level int)INSERT INTO #stack VALUES (@current, 1)SELECT @level = 1 WHILE @level > 0BEGIN IF EXISTS (SELECT * FROM #stack WHERE level = @level) BEGIN SELECT @current = item FROM #stack WHERE level = @level SELECT @line = space(@level - 1) + @current PRINT @line DELETE FROM #stack WHERE level = @level AND item = @current INSERT #stack SELECT child, @level + 1 FROM hierarchy WHERE parent = @current IF @@ROWCOUNT > 0 SELECT @level = @level + 1 END ELSE SELECT @level = @level - 1END -- WHILE
下面是一段前台的写法
procedure Init;
var
tvParent: TTreeNode;
sParent, sCurNode: String;
iIndex: Integer;
begin
lsbColumn.ItemIndex := 0;
with qryReadData do
begin
Close;
SQL.Clear;
SQL.Add( ' Select Parent, Category from PersonCategory ' );
Open;
while Not Eof do
begin
sParent := FieldByName( 'Parent' ).AsString;
sCurNode := FieldByName( 'Category' ).AsString;
tvParent := nil;
for iIndex := 0 to tvCategory.Items.Count - 1 do
begin
if tvCategory.Items[iIndex].Text = sParent then
begin
tvParent := tvCategory.Items[iIndex];
Break;
end;
end;
if tvParent = nil then
begin
tvParent := tvCategory.Items.Add( nil, sParent );
end;
tvCategory.Items.AddChild( tvParent, sCurNode );
Next;
end; for iIndex := 0 to tvCategory.Items.Count - 1 do
begin
if tvCategory.items[iIndex].HasChildren = True then
begin
tvCategory.items[iIndex].ImageIndex := 0;
tvCategory.items[iIndex].SelectedIndex := 0;
end
else
begin
tvCategory.items[iIndex].ImageIndex := 1;
tvCategory.items[iIndex].SelectedIndex := 1;
end;
end
end;
end;
var node :array of TTreenode;
rootnode : TTreenode;
str0,str :string;
Alevel :integer;
begin
str0 := 'select max(level)'
+ ' from epgroup start with groupupid =''-1'''
+ ' connect by groupupid = prior groupid '; str := 'select level,groupid,groupupid,groupname,groupdesc'
+ ' from epgroup start with groupupid =''-1'''
+ ' connect by groupupid = prior groupid ';
with qrypub do begin
close;
sql.Clear;
sql.Add(str0);
open; if fields[0].AsInteger > 0 then
setlength(node,fields[0].AsInteger+1)
else
exit; node[0] := Atree.Items.GetFirstNode; close;
sql.Clear;
sql.Add(str);
open;
while not eof do begin
alevel := fieldbyname('level').asinteger;
node[alevel] := atree.Items.AddChild(node[alevel-1],
fieldbyname('groupid').AsString+'_'+ fieldbyname('groupname').AsString );
next;
end;
result := true;
end;
end;注意:要避免分割符写入ID(这里用下划线 '_'),,速达ERP有这个BUG的:)
从第一条开始
while(记录集有效)
{
if(上级ID的节点已建立)then
createnode(上级ID的节点,flag子节点);
else
if(上级ID的节点 is NULL)then
createnode(NULL,flag子节点); //根节点
else
报错 下条记录
}
'====================================================================================
'描 述:根据父节点加载子节点,
' 先加载领导节点再加载单位节点,若当前加载为单位节点则递归调用加载下属节点。
'编码/修改:1 XXX 2001/08/16 创建
'====================================================================================
Public Sub AddNodeByParent(vParentNode As Node, _
vRecOrg As ADODB.Recordset, _
vRecEmp As ADODB.Recordset)
Dim i As Integer
Dim dicCurrentLeavelNode As New Dictionary '''当前级节点的集合(用于递归)
Dim nNode As Node '''节点
vRecEmp.Filter = "emp_belongorg='" & vParentNode.Key & "' and emp_type='领导'" '''属于该单位的领导
vRecOrg.Filter = "org_belong='" & vParentNode.Key & "'" '''属于该单位的下属单位
If vRecEmp.RecordCount > 0 Then
For i = 1 To vRecEmp.RecordCount '''加载领导节点
Set nNode = mTreeView.Nodes.Add(vParentNode.Key, tvwChild, _
vRecEmp!emp_recid, vRecEmp!emp_name & vRecEmp!emp_title, gCNTLeader)
vRecEmp.MoveNext
Next
End If
If vRecOrg.RecordCount > 0 Then
For i = 1 To vRecOrg.RecordCount '''加载载单位节点
Set nNode = mTreeView.Nodes.Add(vParentNode.Key, tvwChild, _
vRecOrg!org_recid, vRecOrg!org_simname, gCNTOrg)
dicCurrentLeavelNode.Add i, nNode
vRecOrg.MoveNext
Next
End If
For i = 1 To vRecOrg.RecordCount '''递归加载所有子节点
AddNodeByParent dicCurrentLeavelNode.Item(i), vRecOrg, vRecEmp
Next
vRecEmp.Filter = ""
vRecOrg.Filter = ""
Set dicCurrentLeavelNode = Nothing
End Sub
你的代码确实有点用,但如果你改变一下数据结构(加入层次字段,并按此排序),则代码就很简单,返正我是不会用递归的。
------------------------------------------------------------------------------------------------------------
Public Sub MakeTree(tvw as Object,rsData as ADODB.RecordSet)
Dim objNode as Object Set objNode = tvw.Nodes.Add(, , "Root", "所有结点", 1)
objNode.Expanded = True
objNode.Selected = True Do While Not rsSel.EOF
If IsNull(rsData!UpID) Then
Set objNode = tvw.Nodes.Add("Root", 4, "_" & rsData!ID, rsData!Name, 1)
Else
Set objNode = tvw_s.Nodes.Add("_" & rsData!UpID, 4, "_" & rsData!Name, 1)
End If
objNode.Parent.Expanded = True
rsSel.MoveNext
Loop
End Sub
------------------------------------------------------------------------------------------------------------ffossil(吴下阿蒙):
你的方法简直太棒了,这才我想要的,非常感谢,这下好了,不用两个表联起来查了,一次就OK。
让我再分析一下吧,前提是数据按树形顺序依次排列,当处理到某个下级结点时,
它的上级结点必已存放在Item[当前级-1]这个结点中(假设级数都从0开始)。比如有这样一组数据,
X
A
A1
A2
B
B1
B2
B21
C
共有4级,可以定义数据Node:Array [0..3] of TTreeNode,循环时各数据如下:
Node[0] Node[1] Node[2] Node[3]
X X
A A
A1 A1
A2 A2
B B
B1 B1
B2 B2
B12 B12
C C 可以看到,无论处理到哪个结点,Node[当前级-1]的内容都正好是它的父结点。
你的方法简直太棒了,这才我想要的,非常感谢,这下好了,不用两个表联起来查了,一次就OK。
让我再分析一下吧,前提是数据按树形顺序依次排列,当处理到某个下级结点时,
它的上级结点必已存放在Item[当前级-1]这个结点中(假设级数都从0开始)。比如有这样一组数据,
X
A
A1
A2
B
B1
B2
B21
C
共有4级,可以定义数据Node:Array [0..3] of TTreeNode,循环时各数据如下:
Node[0] Node[1] Node[2] Node[3]
X X
A A
A1 A1
A2 A2
B B
B1 B1
B2 B2
B12 B12
C C可以看到,无论处理到哪个结点,Node[当前级-1]的内容都正好是它的父结点。
r=Record
js:integer; //其实此项无用
id:String[5];
sjid:String[5]; //因为有空值,故定义成字符串比较好
mc:String[20];
end;
2. 定义记录数组
ra=Array[0..RecordCount-1] of r;
3. 定义递归过程:
procedure TForm1.dggc(id:string;tn:TTreeNode);
var
mynode: TTreeNode;
i:integer;
begin
for i:=0 to RecordCount-1 do
begin
if ra[i].sjid=id then
begin
mynode:=dxTreeView1.Items.AddChild(tn,ra[i].mc);
dggc(ra[i].id,mynode);
end;
end;
end;
3. 假定数组已赋值,RecordCount为数组长度
procedure TForm1.Button1Click(Sender: TObject);
var
i:Integer;
node:TTreeNode;
begin
for i:=0 to RecordCount-1 do
if ra[i].sjid='' then
begin
node:=dxTreeView1.Items.AddChild(nil,ra[i].id);
dggc(ra[i].id,node);
end;
end;
完成啦!!!