【问题标题】:How to correctly call a vba function如何正确调用vba函数
【发布时间】:2018-07-10 02:36:51
【问题描述】:

我是 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 参数类型不匹配。

【问题讨论】:

  • 更好地解释你正在尝试做什么,因为你的错误代码并不清楚。您的函数不执行任何操作,作为参数传递的变量是通过find 设置的,然后在函数结束时死亡。如果您的函数可以返回两个项目(它不能),那么它们将是 Range 类型,但您的 Cells(Rw, CL) 需要整数作为参数而不是范围。
  • 看看你是否可以修改它以适应(或者更好,只是使用它):rondebruin.nl/win/s9/win005.htm
  • Public Sub FindRange(ByRef Rw As Long, ByRef CL As Long) 但这不是解决问题的最佳方法。

标签: vba excel


【解决方案1】:

考虑:

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

【讨论】:

    【解决方案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
    

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

    【讨论】:

      【解决方案3】:
      Public Function FindRange(Rw As Long, CL As Long)
      Dim Rw As Long
      Dim CL As Long
      

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

      同时删除它们,您的代码应该可以按预期工作,即分配 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会说谎;该答案还列出了执行此操作的各种方法,以及为什么不使用它们。

      【讨论】:

      • 如果工作表中的唯一值在 B99 和 Z2 中,则该单个例程不会返回真正的最后一行/最后一列。
      【解决方案4】:
      1. 设置找到的范围对象。
      2. 将父工作表作为参数传入。 Activesheet 永远不应该在通用函数中使用,无论如何您很快就会停止使用它。
      3. 不要修改你的论点。
      4. 由于您只将新值 byRef 赋予参数,而不是从函数返回值,因此这也可能是一个子过程。
      5. 调暗主变量中的变量。使用选项显式。

      这是根据上面的注释重写的。

      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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-09-27
        • 2021-07-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-10
        • 1970-01-01
        相关资源
        最近更新 更多