如何正确调用VBA函数

时间:2018-07-09 17:28:58

标签: vba excel-vba excel

我是vba的新手,但是我正在尝试创建一个函数,该函数可动态查找整个工作表的范围,以供其他宏用于数据清理。

以下是函数:

Public Function FindRange(Rw As Long, CL As Long)
Dim Rw As Long
Dim CL As Long

CL = ActiveSheet.Cells.Find(What:="*", _
                After:=Range("A1"), _
                LookAt:=xlPart, _
                LookIn:=xlFormulas, _
                SearchOrder:=xlByColumns, _
                SearchDirection:=xlPrevious, _
                MatchCase:=False).Column

Rw = ActiveSheet.Cells.Find(What:="*", _
                After:=Range("A1"), _
                LookAt:=xlPart, _
                LookIn:=xlFormulas, _
                SearchOrder:=xlByRows, _
                SearchDirection:=xlPrevious, _
                MatchCase:=False).Row
End Function

这是我要称呼它的地方:

Sub Range_Find_Method()


Call FindRange(Rw, CL)
ActiveSheet.Range("A1", Cells(Rw, CL)).Select



End Sub

我一直收到不匹配的ByRef参数类型。

4 个答案:

答案 0 :(得分:2)

您不应调用函数,而应将其返回值分配给调用子/函数中的变量。您还应该给函数一个返回类型,例如

Public Function GetUsedRange() As Range
    Set GetUsedRange = ActiveSheet.UsedRange
End Function

也如上面的代码所示,您不能使用

ActiveSheet.UsedRange

要找到使用的单元格范围?! https://msdn.microsoft.com/en-us/vba/excel-vba/articles/worksheet-usedrange-property-excel

我编写的函数本质上是多余的,因为您可以使用

 Dim MyUsedRange As Range
 Set MyUsedRange = ActiveSheet.UsedRange

在这种情况下,除非将结果分配给变量,否则您甚至都不需要去做,除非在代码运行过程中使用的范围发生了变化。

答案 1 :(得分:2)

考虑:

Public Function FindRange()
    Dim Rw As Long
    Dim CL As Long

    CL = ActiveSheet.Cells.Find(What:="*", _
                    After:=Range("A1"), _
                    LookAt:=xlPart, _
                    LookIn:=xlFormulas, _
                    SearchOrder:=xlByColumns, _
                    SearchDirection:=xlPrevious, _
                    MatchCase:=False).Column

    Rw = ActiveSheet.Cells.Find(What:="*", _
                    After:=Range("A1"), _
                    LookAt:=xlPart, _
                    LookIn:=xlFormulas, _
                    SearchOrder:=xlByRows, _
                    SearchDirection:=xlPrevious, _
                    MatchCase:=False).Row
    Dim arr(1 To 2) As Long
    arr(1) = CL
    arr(2) = Rw
    FindRange = arr
End Function

Sub MAIN()
    Dim coor() As Long
    coor = FindRange()
    ActiveSheet.Range("A1", Cells(coor(2), coor(1))).Select
End Sub

enter image description here

答案 2 :(得分:1)

Public Function FindRange(Rw As Long, CL As Long)
Dim Rw As Long
Dim CL As Long

这甚至不应该编译,RwCL局部变量是重复的声明,在这里:

Compile error: duplicate declaration in current scope

同时删除它们,您的代码应能按预期工作,即分配ByRef 参数 RwCL ...,它们都可以使用更具描述性的名称和显式的ByRef修饰符(如果未指定,则为隐式)。

另外,正如其他人所暗示的,函数应该返回值。您可以通过在函数签名中指定返回类型来做到这一点...

Public Function FindRange(ByVal inRow As Long, ByVal inColumn As Long) As Range

...然后在该函数的主体中分配该函数的标识符:

    Set FindRange = result ' where result is a Range object reference

使用ByRef参数作为返回值是可行的,但是当过程为Function时,则需要使用相当混乱的API。将其设为Sub过程将消除关于返回值可能是什么的模糊性,再次命名可以使意图更清晰:

Public Sub FindRange(ByRef outRow As Long, ByRef outColumn As Long)

您正在进行的Range.Find方法调用是假设将找到一个单元格-如果对一个空工作表调用该单元格,则会因运行时错误91而崩溃。 从不假设Range.Find将返回有效的对象引用-将其结果存储在Range对象引用中,并验证其是否为Nothing

Dim result As Range
Set result = ActiveSheet.Cells.Find(What:="*", _
                                    After:=Range("A1"), _
                                    LookAt:=xlPart, _
                                    LookIn:=xlFormulas, _
                                    SearchOrder:=xlByColumns, _
                                    SearchDirection:=xlPrevious, _
                                    MatchCase:=False)
If Not result Is Nothing Then
    outRow = result.Row
    outColumn = result.Column
End If

作为奖励,您可以避免打相同的电话两次。但是再一次,请考虑只返回result范围:

Set FindRange = result

最后,在here中查找一种实际上可靠的方法来检索工作表上的最后一行/列。 UsedRange能说谎。该答案还列出了执行此操作的各种方法,以及为什么不使用它们。

答案 3 :(得分:0)

  1. 设置找到的范围对象。
  2. 将父级工作表作为参数传递。 Activesheet永远不能在通用函数中使用,并且无论如何您都将很快停止使用它。
  3. 不要重新提出自己的观点。
  4. 由于您仅将新值byRef分配给参数,而不从函数中返回值,因此这也可能是子过程。
  5. 将vars调入您的main中。明确使用选项。

这里是根据上述说明进行的重写。

Public sub FindRange(ws as worksheet, byref Rw As Long, byref CL As Long)
    with ws
        CL = .Cells.Find(What:="*", _
                         After:=.cells(1), _
                         LookAt:=xlPart, _
                         LookIn:=xlFormulas, _
                         SearchOrder:=xlByColumns, _
                         SearchDirection:=xlPrevious, _
                         MatchCase:=False).Column

        Rw = .Cells.Find(What:="*", _
                         After:=.cells(1), _
                         LookAt:=xlPart, _
                         LookIn:=xlFormulas, _
                         SearchOrder:=xlByRows, _
                         SearchDirection:=xlPrevious, _
                         MatchCase:=False).Row
    end with
End sub

Sub Range_Find_Method()

    Dim Rw As Long
    Dim CL As Long

    FindRange ActiveSheet, Rw, CL
    ActiveSheet.Range("A1", ActiveSheet.Cells(Rw, CL)).Select

End Sub

LoadLibrary out of kernel32