【问题标题】:A Function that returns 0, when the same function executed as a sub returns the correct value返回 0 的函数,当作为子执行的相同函数返回正确值时
【发布时间】:2018-04-03 16:37:40
【问题描述】:

以下函数在工作簿中使用时返回 0 值或 #VALUE,尽管作为子函数执行时返回正确的值。我尝试创建一个将以下代码作为子代码返回的函数,但我得到了相同的结果。我的函数搜索工作簿中的每个工作表,找到以“Budget*”开头的表格,并将单元格添加到用户指定的列中。张数未知,因此无法尝试将此函数编写为单元格的实际值。我被难住了!

Example1Example2

Function IncomeSum(Month)

ColumnNumber = Month.Column
IncomeMonthSum = 0
Dim WS As Worksheet

For Each WS In Worksheets
    If WS.Tab.Color = 255 Then Exit For
    If WS.Index >= 4 Then

        For Each Tbl In WS.ListObjects
            If Tbl.Name Like "Budget*" Then
            TableName = Tbl.Name
            Exit For
            End If
        Next Tbl

    ColumnSum = Application.WorksheetFunction.Sum(Range(TableName & "[[#All],[Column" & ColumnNumber & "]]"))
    IncomeMonthSum = IncomeMonthSum + ColumnSum
    End If
Next WS

IncomeSum = IncomeMonthSum

End Function

【问题讨论】:

  • UDF 不能Activate 其他工作表,例如。不要反对ActiveSheet。使用For Each ws In Worksheets 迭代Worksheets 集合,然后使用ws 而不是ActiveSheetSheets 集合不保证只包含 Worksheet 对象;当您迭代 Sheets 集合时,WS 可以是从 Chart 到任何六种旧工作表类型中的任何一种。
  • 同样Month 被假定为一个Range 对象,但是该函数没有为它声明一个类型,所以它很乐意接受Variant 可以容纳的任何东西(即字面上任何东西)。,并在Month.Column上出现运行时错误,而不是Range:明确声明参数As Range以避免这种情况。函数的返回值也应该是As Long,或As Double,或任何合适的值。它当前返回一个隐含的Variant。变量WS 也应该被声明。 Dim ws As Worksheet.
  • 您的代码也存在逻辑问题:如果任何工作表都没有名称中包含 Budget 的表格,则您的最后一个 ColumnSum 将再次添加到 IncomeMonthSum 中。我强烈建议您使用Option Explicit 选项
  • 感谢您的意见! @MathieuGuindon,我提出了您的编辑建议,但公式仍然给出值 0。我不明白,函数不能像 sub 那样执行方法吗?查看我更新的代码以查看我所做的编辑。 Zac,我完全理解,但是,以我构建工作簿的方式,工作表不可能没有名为“Budget”的表。我不会打扰额外的代码。
  • WS.Activate 在 UDF 中是非法的。是的,确实,从单元格公式调用的函数不能完成子/宏可以做的所有事情。函数接受输入、计算值、输出结果——仅此而已。

标签: vba excel


【解决方案1】:

您的函数存在几个问题,主要问题是 WS.Activate,然后与 ActiveSheet 发生冲突。您有一个 WS 工作表对象 - 使用它;不允许 UDF Activate 工作表。

那么,您并没有声明您正在使用的变量。这意味着您距离破坏所有内容只有 1 个错字,并且您不会获得使用正确类型的对象变量所获得的所有 IntelliSense。在模块顶部指定Option Explicit,并为每个局部变量指定Dim 语句。不管你把 Dim 语句放在哪里,它们都是不可执行的——我的建议是让它们尽可能接近它们的第一个任务。

TableName 将在WS 迭代之间保留其先前的值,这意味着即使WS 没有表,您的代码也会尝试使用先前迭代的TableName。在迭代之间重置它(或者更好的是,提取一个私有函数,给你一个ListObject,给定一个Worksheet)。

Option Explicit

Public Function IncomeSum(ByVal Month As Range) As Double

    Dim ColumnNumber As Long
    ColumnNumber = Month.Column

    Dim WS As Worksheet        
    For Each WS In ThisWorkbook.Worksheets
        If WS.Tab.Color = 255 Then Exit For
        If WS.Index >= 4 Then
            Dim Tbl As ListObject
            Dim TableName As String
            For Each Tbl In WS.ListObjects
                If Tbl.Name Like "Budget*" Then
                    TableName = Tbl.Name
                    Exit For
                End If
            Next Tbl

            If TableName <> vbNullString Then
                Dim ColumnSum As Double
                ColumnSum = Application.WorksheetFunction.Sum(WS.Range(TableName & "[[#All],[Column" & ColumnNumber & "]]"))

                Dim IncomeMonthSum As Double
                IncomeMonthSum = IncomeMonthSum + ColumnSum

                TableName = vbNullString
            End If
        End If
    Next WS

    IncomeSum = IncomeMonthSum

End Function

您有一个ListObject - 假设正确验证了提供的Month 范围,您可以使用Tbl.ListColumns(Month.Column).DataBodyRange 而不是硬编码表格公式。

【讨论】:

    猜你喜欢
    • 2011-08-23
    • 1970-01-01
    • 1970-01-01
    • 2021-10-02
    • 1970-01-01
    • 1970-01-01
    • 2018-04-28
    • 1970-01-01
    • 2018-08-07
    相关资源
    最近更新 更多