ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 Excel Home精品图文教程库
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
300集Office 2010微视频教程 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 5481|回复: 47

[求助] 15楼里 DTQY 的代码,等老师您来修改和完善

[复制链接]

TA的精华主题

TA的得分主题

发表于 2020-3-14 09:24 | 显示全部楼层 |阅读模式
本帖最后由 玉阳山人 于 2020-3-16 16:37 编辑

1.gif
动态区域.zip (33.36 KB, 下载次数: 5)

在对同一类型的多个类似工作表进行统计计算时,经常会遇到因为行、列区域不等的制约,导致无法复制公式的现象发生,无奈得频繁修改公式的统计区域--如果工作表很多,既麻烦又很容易出错,能不能创建一个动态区域的自定义函数,使之能够按照指定行号、列标,来自动扩展需要统计的数据区域大小呢?

   如附件所示,只需在各种统计公式里内嵌一个DTQY的子程序,输入指定的行号、列标,即可自动扩展成统计所需要的即时单元格区域,这样就方便多了!

   敬请老师们按附件里的运算规则和要求,创建这个自定义函数。

重要提示:
1.《示例说明》中R5:S22,J23:Q24里展示的单元格地址,只是为了用于说明数据区域和指定范围所代表的的单元格地址引用范围的差别,实际上,R5:S22,J23:Q24并不能直接显示单元格地址,只有在外套统计函数后,显示与外套函数统计功能相对应的统计计算结果;如在T5中输入=SUM(DTQY(5,22,,,0)),显示的是对数据区域J5:P5的求和结果 29                                                         

2.R21和Q23,由于其指定范围内尚没有输入任何数据,按说数据区域应该为空,此两个单元格本应设置为空白才符合运算规则,但外套诸如SUM......等函数后,就相当于SUM(    )  【即:统计函数没有输入单元格区域】,其计算结果肯定会显示错误!不得已才借用指定范围代替数据区域,但总觉得不合适。
    老师们如果有办法让其外套统计函数后,最终  要么显示正确的统计结果,要么屏蔽错误结果为空白!则更符合本意!如此,则修改运算规则为:当指定范围内尚没有输入任何数据,则该指定范围的数据区域设置为空白【即:示例说明的R21和Q23单元格】!

3.根据以往经验,此类自定义函数,很容易出现--当指定范围内的数据发生变化时,新扩展区域的计算结果有时不会自动刷新--的问题,这一点应引起注意。

4.额外想要的功能当DTQY没有外套函数的前提下,如果在J23输入=DTQY(5,22,"J") 右拉,或R5输入DTQY("J","Q",5)下拉,显示的即是如【J23:Q23】或(R5:R22】那样的数据区域的起止范围;
                                                                            如果输入J24输入=DTQY(5,22,"J",,1)右拉,或S5输入DTQY("J","Q",5,,1)下拉,显示的即是如【J24:Q24】或(S5:S22】那样的指定范围的起止范围。

最新附件在15楼。






评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2020-3-14 09:48 | 显示全部楼层
楼主直接跨过了程序员,到达了下一站,架构师~~~~这点大部分的程序员是迈不上这台阶的~~~~

TA的精华主题

TA的得分主题

 楼主| 发表于 2020-3-14 12:08 | 显示全部楼层
敬请老师们按照运算规则和要求,创建这个自定义函数。

TA的精华主题

TA的得分主题

 楼主| 发表于 2020-3-14 14:16 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
敬请老师们按照运算规则和要求,创建这个自定义函数。

TA的精华主题

TA的得分主题

发表于 2020-3-14 16:36 | 显示全部楼层

TA的精华主题

TA的得分主题

 楼主| 发表于 2020-3-14 20:09 | 显示全部楼层
再顶!

敬请老师们按照运算规则和要求,创建这个自定义函数。

TA的精华主题

TA的得分主题

 楼主| 发表于 2020-3-15 07:05 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
敬请老师们编写代码。

TA的精华主题

TA的得分主题

 楼主| 发表于 2020-3-15 10:43 | 显示全部楼层

TA的精华主题

TA的得分主题

 楼主| 发表于 2020-3-15 13:51 | 显示全部楼层

TA的精华主题

TA的得分主题

 楼主| 发表于 2020-3-15 18:07 | 显示全部楼层
本帖最后由 玉阳山人 于 2020-3-15 21:53 编辑

1.gif

能够自动刷新的动态区域.zip (61.13 KB, 下载次数: 2)

代码如下:
Function DTQY(StartID As Variant, EndID As Variant, Optional RowOrColID As Variant = "", Optional shName As String = "", Optional intAll As Integer = 0) As Variant
    Application.Volatile '声明为易失性函数
    Dim rgCur As Range, strRowOrColID As String, strSelType As String
    Dim lngCurRow As Long, lngCurCol As Long
    Dim SelRow_Start As Long, SelRow_End As Long
    Dim SelCol_Start As Long, SelCol_End As Long
    Dim SelSh As Worksheet, arrResult As Variant

    '取得公式所在单元格的信息
    Set rgCur = Application.Caller
    lngCurRow = rgCur.Row
    lngCurCol = rgCur.Column
    '获取工作表
    If Trim(shName) = "" Then
        Set SelSh = rgCur.Worksheet
    Else
        Set SelSh = GetShByName(Trim(shName))
    End If
    If SelSh Is Nothing Then
        DTQY = "表名不存在"
        Exit Function
    End If

    '判断参数类型
    If IsNumeric(StartID) Then
        strSelType = "ROW"
    Else
        strSelType = "COL"
    End If
    '如果参数1与参数2类型不一致,退出
    If IsNumeric(StartID) <> IsNumeric(EndID) Then
        DTQY = "参数1、2类型不一致"
        Exit Function
    End If
    '如果参数1、2的类型与参数3相同,退出
    If RowOrColID <> "" And (IsNumeric(StartID) = IsNumeric(RowOrColID)) Then
        DTQY = "参数3类型不对"
        Exit Function
    End If

    '如果行号参数不对,退出
    If IsNumeric(StartID) And (Val(StartID) < 1 Or Val(StartID) > Rows.Count) Then
        DTQY = "参数1设置有误"
        Exit Function
    End If
    If IsNumeric(EndID) And (Val(EndID) < 1 Or Val(EndID) > Rows.Count) Then
        DTQY = "参数2设置有误"
        Exit Function
    End If

    '设置第三参数
    strRowOrColID = Trim(UCase(RowOrColID))
    '根据传入的参数,设置区域参数
    Select Case strSelType
        Case "ROW" '设置参数为行号
            SelRow_Start = Val(StartID) '起始行
            SelRow_End = Val(EndID) '结束行
            '根据第三参数获取列号
            If strRowOrColID <> "" Then
                lngCurCol = GetColIDByStr(strRowOrColID)
            End If
            '列号有误,退出
            If lngCurCol = 0 Then
                DTQY = "参数3设置有误"
                Exit Function
            End If

            If intAll <> 0 Then SelRow_End = SelSh.Cells(SelRow_End, lngCurCol).End(xlUp).Row

            '返回选择区域
            Set arrResult = SelSh.Range(SelSh.Cells(SelRow_Start, lngCurCol), SelSh.Cells(SelRow_End, lngCurCol))
        Case "COL" '设置参数为列号
            SelCol_Start = GetColIDByStr(CStr(StartID)) '起始列
            SelCol_End = GetColIDByStr(CStr(EndID)) '结束列
            If SelCol_Start * SelCol_End = 0 Then
                DTQY = "参数1、2设置有误"
                Exit Function
            End If
            '根据第三参数获取行号
            If strRowOrColID <> "" Then
                lngCurRow = Val(strRowOrColID)
            End If
            '行号有误,退出
            If lngCurRow < 1 Or lngCurRow > Rows.Count Then
                DTQY = "参数3设置有误"
                Exit Function
            End If


          If intAll <> 0 Then SelCol_End = SelSh.Cells(lngCurRow, SelCol_End).End(xlToLeft).Column
            '返回选择区域
            Set arrResult = SelSh.Range(SelSh.Cells(lngCurRow, SelCol_Start), SelSh.Cells(lngCurRow, SelCol_End))
    End Select

    '返回最终结果区域
    Set DTQY = arrResult
End Function

'根据列名,返回列标索引
Private Function GetColIDByStr(strColName As String) As Long
    Dim strAddress  As String, lngLen As Long
    Dim lngIndex As Long, strChar As String
    Dim lngColID As Long

    strAddress = Trim(UCase(strColName))
    lngLen = Len(strAddress)

    For lngIndex = 1 To lngLen
        strChar = Mid(strAddress, lngIndex, 1)
        If Asc(strChar) < 65 Or Asc(strChar) > 90 Then
            GetColIDByStr = 0
            Exit Function
        End If
        lngColID = lngColID + (((Asc(strChar) - 65) Mod 26) + 1) * (26 ^ (lngLen - lngIndex))
    Next

    If lngColID > Columns.Count Then
        GetColIDByStr = 0
        Exit Function
    End If

    GetColIDByStr = lngColID
End Function

'根据表名返回工作表
Private Function GetShByName(strShName As String) As Worksheet
    Dim sh As Worksheet
    For Each sh In Sheets
        If sh.Name = strShName Then
            Set GetShByName = sh
            Exit Function
        End If
    Next
    Set GetShByName = Nothing
End Function



曾经有老师写过上边的代码,验证时有个Bug,经过两天来的反复测试,终于找到了代码出错的原因:当实际上的数据区域,小于第2参数限定的指定范围时,计算的结果才会正确;而唯独只在 1.  数据区域=指定范围  2. 指定范围内没有数据 的情况下才会出错。

那么,1.只需再增加一个判断语句:当数据区域的最后行、列与参数2指定的范围相同时,则指定范围代替数据区域进行统计计算就行了吧?     如:T5:T22中指定范围是DTQY("J","Q",,,1),代表对J:Q列里的各行数据进行统计,从上图看出,指定范围的最后一列Q5:Q22里,哪一行若没有数据,则T5:T22的哪一行计算结果就正确;哪一行有数据,T5:T22的哪一行计算结果就不对。
   模块1的代码里,If intAll <> 0 Then SelRow_End = SelSh.Cells(SelRow_End, lngCurCol).End(xlUp).Row  这一句好像是代表最后数据行;而  If intAll <> 0 Then SelCol_End = SelSh.Cells(lngCurRow, SelCol_End).End(xlToLeft).Column 则是代表最后数据列;

麻烦老师们在这两句后面,各增加一句判断代码---当指定范围内尚没有任何数据或者数据区域正好等于指定范围时,则用指定范围代替数据区域进行统计计算,这样就能保证计算结果始终正确了!



您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

关闭

最新热点上一条 /1 下一条

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-4-24 07:42 , Processed in 0.041605 second(s), 16 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

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