设为首页收藏本站Access中国

Office中国论坛/Access中国论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

12下一页
返回列表 发新帖
查看: 6255|回复: 15
打印 上一主题 下一主题

[模块/函数] 【Access小品】越俎代庖 --- 递归函数示例

[复制链接]
跳转到指定楼层
1#
发表于 2015-6-4 15:16:28 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 todaynew 于 2015-6-6 12:44 编辑

  越俎代庖这个成语中有两个角色,一个是神汉一个大厨,意思是说在祭祀活动中神汉和大厨是有分工的,神汉不应直接代替大厨的工作。在Vba中实现一些功能,也有两种东西,一个叫做子程序(Sub),一个叫做函数(Function)。子程序用来完成某些动作,函数用来返回需要的数据,通常来说这样理解没什么大的问题。不过有时候我们需要用函数来越俎代庖,实现子程序完成某些动作的功能。

  从道理上讲,函数是可以替代子程序的。原因在于函数体和子程序体的构成是没有什么大的差别的,唯一不同的是函数体中可以存在一条返回数据的语句。也就是说子程序能实现的功能,函数都是可以实现的。而函数能实现的功能,子程序并不一定都能实现。这样说来,子程序的存在只是为了保留一种概念上的功能区分。

  版友付谦同志昨日里问了一个关于家谱用TreeView呈现方面的问题。我们知道家谱是一个不定级的层次结构,最适于用递归的方法来得到一个树形结构。所以我们通常可以用一个递归子程序来实现TreeView节点的加载。假如我们希望在每个节点上,反映出这个节点的所有后代成员的总数,这就不是一个简单的事情了。说它不简单,是因为它所要做的动作是向节点的Text属性写入一个统计出来的数据,递归动作本身比较难以统计这个数据。在这个特定的情况下,递归子程序比较难以实现边统计边写入的功能。

  怎么办呢?答案很简单,将递归子程序改为递归函数,这个问题就很简单的可以解决了。函数是可以一边做一些动作,一边进行计算并返回数据的,这些返回的数据可以容易的参与递归运算。我们可以将代码大体写成如下:

Private Function SetNodes(ByRef tree As TreeView, ByRef n As Node) As Long
    Dim cn As Node
    Dim rs As New ADODB.Recordset
    Dim ssql As String
    Dim i As Long
    Dim cnt As Long

    ssql = "select * from 族人信息 where " & n.Tag
    rs.Open ssql, CurrentProject.Connection, adOpenKeyset, adLockOptimistic

    cnt = rs.RecordCount
    For i = 1 To rs.RecordCount
        Set cn = tree.Nodes.Add(n.Key, 4, "b" & rs!族人代码.Value, rs!姓名.Value)
        cn.Tag = "nz(父代码,0)=" & rs!族人代码.Value
        '递归运算
        cnt = cnt + SetNodes(tree, cn)
        rs.MoveNext
    Next
    '写入节点的Text属性
    n.Text = n.Text & " (" & n.Children & "/" & cnt & ")"

    SetNodes = cnt

    rs.Close: Set rs = Nothing
    Set cn = Nothing
End Function


示例:

视图:






本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

本帖被以下淘专辑推荐:

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏2 分享分享 分享淘帖1 订阅订阅
2#
发表于 2015-6-5 13:35:33 | 只看该作者
谢谢分享.
回复

使用道具 举报

3#
发表于 2015-6-6 08:39:56 | 只看该作者
谢todaynew 大师,与君一席话,胜读十年书。
4#
发表于 2015-6-10 15:47:42 | 只看该作者
请问todaynew大师在子窗体中,怎么按照递归的直接层别排序。建个临时表,想了半天,也搞不出,能否做个例子,达到如下效果

层次 族人代码 世代 姓名 关系
4 20226 24 杨云 长子
5 20228 25 杨琳 长女
5 20229 25 杨琼 次女
5 20230 25 杨泽 之子
4 20227 24 刘菊 配
4 20231 24 杨妹 之女
4 20232 24 杨许 次子
5 20234 25 杨鹏顺 之子
4 20233 24 曾艳 配
5#
 楼主| 发表于 2015-6-10 20:48:49 | 只看该作者
13601812106_01 发表于 2015-6-10 15:47
请问todaynew大师在子窗体中,怎么按照递归的直接层别排序。建个临时表,想了半天,也搞不出,能否做个例子 ...

很简单嘛
1、将表中的查询标识字段的数据类型修改为文本型;

2、子窗体数据源修改为:SELECT * FROM 族人信息 ORDER BY 查询标识, 族人代码;

3、将子程序FormFilter和SetWh做如下修改:
Private Sub FormFilter()
    Dim n As Node
    Dim wh As String
    Dim pid As Long
   
    Set n = Me.TreeView0.SelectedItem
    wh = "false"
    If Me.选项.Value = 1 Then
        wh = n.Tag
    Else
        CurrentDb.Execute "update 族人信息 set 查询标识=Null"
        pid = Val(Mid(n.Key, 2))
        Call SetWh(pid, "00")
        wh = "nz(查询标识,'')<>''"
    End If
    Me.子窗体.Form.Filter = wh
    Me.子窗体.Form.FilterOn = True
    Set n = Nothing
End Sub

Private Sub SetWh(ByVal pid As Long, ByVal num As String)
    Dim ssql As String
    Dim rs As New ADODB.Recordset
    Dim i As Long
    Dim str As String

    ssql = "select * from 族人信息 where 父代码=" & pid & " order by 族人代码"
    rs.Open ssql, CurrentProject.Connection, adOpenKeyset, adLockOptimistic
    For i = 1 To rs.RecordCount
        rs!查询标识.Value = num & Format(i, "00")
        rs.Update
        Call SetWh(rs!族人代码.Value, rs!查询标识.Value)
        rs.MoveNext
    Next
   
    rs.Close: Set rs = Nothing
End Sub

6#
发表于 2015-6-11 10:01:57 | 只看该作者
todaynew 大师,改写的代码也那么优美,真应开个专栏,让更多的人来学习
7#
发表于 2015-6-12 10:37:35 | 只看该作者
todaynew 发表于 2015-6-10 20:48
很简单嘛
1、将表中的查询标识字段的数据类型修改为文本型;

todaynew大师,可以再改造一下吗,目的是输入方便:
1,把一张表,分为两张,一为族人表,二为族人信息表,
2族人信息表中,没有父代码为空的。
3’树控来源为族人表,子窗体来源于族人信息表
附件中,我已做好,就是不知道怎么改,这方面实在太差

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
8#
 楼主| 发表于 2015-6-12 20:55:55 | 只看该作者
本帖最后由 todaynew 于 2015-6-12 20:56 编辑
13601812106_01 发表于 2015-6-12 10:37
todaynew大师,可以再改造一下吗,目的是输入方便:
1,把一张表,分为两张,一为族人表,二为族人信息表 ...

多此一举,呵呵。我不想费功夫做无意义的事情。
9#
发表于 2015-7-20 14:43:25 | 只看该作者
学习学习,谢谢分享! 学习学习,谢谢分享! #在这里快速回复#
10#
发表于 2015-7-20 14:55:42 | 只看该作者
学习学习,谢谢分享!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|站长邮箱|小黑屋|手机版|Office中国/Access中国 ( 粤ICP备10043721号-1 )  

GMT+8, 2024-4-19 22:51 , Processed in 0.118104 second(s), 36 queries .

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表