ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

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

[求助] 能够按指定行号、列标,动态扩展统计区域的内嵌自定义函数

[复制链接]

TA的精华主题

TA的得分主题

 楼主| 发表于 2020-3-12 18:45 | 显示全部楼层
本帖最后由 玉阳山人 于 2020-3-12 22:03 编辑

------------------------------------------------------

TA的精华主题

TA的得分主题

 楼主| 发表于 2020-3-15 17:53 | 显示全部楼层
lsdongjh 发表于 2019-11-12 08:55
1、要有一些基本常识,字符型 与 数值型【DTQY("J","Q")】
2、原来考虑是简单的处理,返回的是数组,给你 ...

1.gif

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

老师:经过两天来的反复测试,终于找到了DTQY原代码出现错误的根源。当实际上的数据区域,小于第1~3参数指定的范围时,计算的结果都正确!唯独只在   数据区域=指定范围    情况下才会出错。

那么,只需再增加一个判断语句:当数据区域的最后行、列与参数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 则是代表最后数据列;

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


代码如下:


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


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

本版积分规则

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

GMT+8, 2024-5-18 05:50 , Processed in 0.030406 second(s), 10 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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