【问题标题】:Get one cell from passed column/row/range VBA Excel从传递的列/行/范围 VBA Excel 中获取一个单元格
【发布时间】:2014-01-14 07:44:34
【问题描述】:

我正在为 VBA 中的 excel 编写用户定义的函数。

用户可以将一整列/整行而不是一个单元格传递给函数。如何获取函数所在的同一行(对于列案例)和同一列(对于行案例)中的单元格。

例如,当您在 Excel 中写入单元格时,例如 C3,公式“=A:A*B:B”实际上计算的是 A3*B3。我希望在我的 UDF 中具有相同的行为。

为了简单起见,我们假设函数返回传递的参数。 此代码不起作用(为列/行/范围返回 #VALUE!):

Public Function MyTestFunction(ByVal arg1) As Variant
    MyTestFunction = arg1
End Function

我的选项如下,但我担心性能以及用户可能希望将值传递给公式而不是 Range。

Public Function MyTestFunction2(ByVal arg1 As Range) As Variant

    If arg1.Count = 1 Then
        MyTestFunction2 = arg1.Value
    Else
        ' Vertical range
        If arg1.Columns.Count = 1 Then
            MyTestFunction2 = arg1.Columns(1).Cells(Application.Caller.Row, 1).Value
            Exit Function
        End If

        ' Horizontal range
        If arg1.Rows.Count = 1 Then
            MyTestFunction2 = arg1.Rows(1).Cells(1, Application.Caller.Column).Value
            Exit Function
        End If

        ' Return #REF! error to user
        MyTestFunction2 = CVErr(xlErrRef)
    End If

End Function

你如何解决这个问题?


感谢宝贵的 cmets 代码已略微更新,现在可用于其他公式来过滤输入值。

Public Function MyTestFunction2(ByVal arg1) As Variant

    If Not TypeName(arg1) = "Range" Then
        MyTestFunction2 = arg1
        Exit Function
    End If


    If arg1.Count = 1 Then
        MyTestFunction2 = arg1.Value
    Else
        ' Vertical range
        If arg1.Columns.Count = 1 Then
            ' check for range match current cell
            If arg1.Cells(1, 1).Row > Application.Caller.Row Or _
                arg1.Cells(1, 1).Row + arg1.Rows.Count - 1 < Application.Caller.Row Then
                ' Return #REF! error to user
                MyTestFunction2 = CVErr(xlErrRef)
                Exit Function
            End If

            ' return value from cell matching cell with function
            MyTestFunction2 = arg1.Worksheet.Columns(1).Cells(Application.Caller.Row, arg1.Column).Value
            Exit Function
        End If

        ' Horizontal range
        If arg1.Rows.Count = 1 Then
            ' check for range match current cell
            If arg1.Cells(1, 1).Column > Application.Caller.Column Or _
                arg1.Cells(1, 1).Column + arg1.Columns.Count - 1 < Application.Caller.Column Then
                ' Return #REF! error to user
                MyTestFunction2 = CVErr(xlErrRef)
                Exit Function
            End If

            ' return value from cell matching cell with function
            MyTestFunction2 = arg1.Worksheet.Rows(1).Cells(arg1.Row, Application.Caller.Column).Value
            Exit Function
        End If

        ' Return #REF! error to user
        MyTestFunction2 = CVErr(xlErrRef)
    End If

End Function

【问题讨论】:

  • 在第一个代码中 sn -p 将MyTestFunction = arg1 更改为Set MyTestFunction = arg1。还要添加一个小机制来识别arg1TypeName(),并确保该函数正在接收范围。然后转到您的电子表格并在任意行输入MyTestFunction(A:A),您将从传递给位于同一行的函数的列中收到等效值。
  • 关于获得与=A:A*B:B 类似行为的第二个想法可以使用Public Function MyTestFunction2(ParamArray arr() As Variant) 然后在新行MyTestFunction2 = arr(0) 和关闭函数End Function 上实现
  • 非常感谢您在评论中的第一句话。它正是我需要的功能。看来它甚至不需要任何进一步的检查。
  • @mehow 如果您可以将您的 cmets 转换为答案,我会结束这个问题。

标签: vba excel arguments


【解决方案1】:

在第一个代码中 sn -p 将 MyTestFunction = arg1 更改为 Set MyTestFunction = arg1。还要添加一个小机制来识别arg1TypeName(),并确保该函数正在接收Range 类型的对象。

Public Function MyTestFunction(ByVal arg1) As Variant
    Set MyTestFunction = arg1
End Function

例子


然后,如果您进入电子表格并在任意行输入=MyTestFunction(A:A),您将收到来自您传递给位于同一行的函数的列的等效值。

您的第二个想法是获得与 =A:A*B:B 类似的行为,您可以使用

Public Function MyTestFunction2(ParamArray arr() As Variant) 
    MyTestFunction2 = arr(0)
End Function

例子

【讨论】:

    【解决方案2】:

    我认为您需要使用Application.ThisCell property 来执行此操作。根据 MSDN:

    Application.ThisCell- 返回用户定义的单元格 函数作为 Range 对象被调用。

    让我在简单的例子中介绍如何使用它。 想象一下,我们在 A:B 列中有如下所示的数据,我们希望分别获得来自 =A*B 的每一行的结果。

    在这种情况下,你需要下面的函数,并以这种方式将它放在C列的下一个:=MyTestFunction(A:A,B:B)

    Function MyTestFunction(rngA As Range, rngB As Range)
    
        Dim funRow As Long
            funRow = Application.ThisCell.Row
        MyTestFunction = rngA(funRow) * rngB(funRow)
    
    End Function
    

    请记住,如果您从其他 VBA 过程调用您的函数,Application.ThisCell 将不起作用。

    【讨论】:

    • 谢谢你。小心直接取 rngA(funRow) 和 rngB(funRow),不要先取一整列。这是因为用户可能想要放置一个像 A2:A6*B2:B6 这样的范围而不是 A:A*B:B (用户可能非常难以预测!)。在这种情况下,将从第二个工作表行开始应用 funRow,而不是从工作表的开头。
    • @Eduard3192993,我知道,我很高兴你也知道这种风险。这是您想要的答案吗?
    • 我正在寻找的答案是我给我的答案。
    • @KazJaw 请注意您的函数有两个参数,并且有一个硬编码的* 乘法因子。这并不是=A:A*B:B 的真正接近行为
    • @mehow,我同意,这是唯一可能的想法,可以合并到 UDF 中。我真的很喜欢您的 cmets,如果您将它们转换为答案,我会很高兴为它投票。
    猜你喜欢
    • 1970-01-01
    • 2016-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多