使用不同工作簿的通用函数过程

时间:2017-11-07 15:44:05

标签: excel-vba function procedure vba excel

我正在努力获得更好的编码实践并使用通用功能 我正在使用主文件中的几个工作簿。 例如,如果我想获取最后一行,我使用以下代码行。

LastRow=Range("A" & Rows.Count).End(xlUp).Row 

要使用函数检索值,我构建函数:

-Function 1

Function GetLastRow() As Integer
GetLastRow = Range("A" & Rows.Count).End(xlUp).Row
End Function 

现在我的Sub Main()我想将GetLastRow()用于不同的工作簿或工作表。我认为在调用我的函数之前Activate工作簿并不是一件好事。

然后我应该每次将工作簿名称和工作表编号发送到我的函数并将我的函数更改为:

-Function 2

Function GetLastRowIn(sWb As String, iWs As Integer) As Integer
GetLastRowIn = Workbooks(sWb).Worksheets(iWs).Range("A" & Rows.Count).End(xlUp).Row
End Function

或者是否有一种更好/更简单的方法来传输工作簿和工作表,我想在其中保留它而不像函数1中那样使用函数?

感谢您的回答!

1 个答案:

答案 0 :(得分:0)

为了使功能更通用,您可以允许一些灵活性,
但也为函数调用强加了一些争论

通用功能

Option Explicit

Public Function GetLastRow(ByRef ws As Worksheet, Optional ByVal fromCol As Long = 1) As Long
    Dim invalidWS As Boolean, lastRow As Long

    If Not ws Is Nothing Then   'check 1st param

        On Error Resume Next    'check that ws reference is valid (delted WS invalidates ws)
            invalidWS = Len(ws.Name) > 0
            invalidWS = Err.Number <> 0  'No error if Err.Number = 0
        On Error GoTo 0

        If Not invalidWS Then
            If fromCol > 0 And fromCol <= ws.Columns.Count Then 'validate 2nd param
                lastRow = ws.Cells(ws.Rows.Count, fromCol).End(xlUp).Row
                'check if WS.fromCol is empty
                If lastRow = 1 And Len(ws.Cells(1, fromCol)) = 0 Then lastRow = 0
            End If
        End If
    End If
    GetLastRow = lastRow
End Function

测试子

Public Sub TestGetLastRow()

    'show results in the Immediate Window (VBA Editor: Ctrl+G)
    Debug.Print GetLastRow(Sheet1, 1)                               'CodeName of WS
    Debug.Print GetLastRow(Workbooks(1).Worksheets(1))              'WS Index
    Debug.Print GetLastRow(ActiveWorkbook.Worksheets("Sheet3"), 3)  'WS name (string)
    Debug.Print GetLastRow(ThisWorkbook.Worksheets(1), 0)           'invalid column (or -3)

    Dim ws As Worksheet
    Set ws = Sheet3
        Application.DisplayAlerts = False
        ws.Delete                           'invalidate ws variable
        Application.DisplayAlerts = True
    Debug.Print GetLastRow(ws, 1)           'function call with invalid ws object
End Sub
  • 始终使用Option Explicit允许编译器捕获变量名称中的拼写错误
  • 验证所有输入
    • 函数调用可能不包含有效的工作表或列号
  • 允许CodeName,WS索引或WS名称(字符串)
  • 指定工作表
  • 通过对第二个参数
  • 使用Optional来允许默认列ID
  • 执行调用以仅将Worksheet对象作为第一个参数发送
    • 如果您接受字符串,则需要先检查工作表(&#34;无效&#34;)是否存在
  • 按索引对请求列进行调用
    • 如果您允许列ID中的字符串,则需要检查字符串是否在&#34; A&#34;和&#34; XFD&#34;
      • 字符串长度介于1和3之间,也不允许使用&#34; XYZ&#34;
      • 等字符串
      • 这需要一个单独的函数来检查字符串
      • 中的每个字母
      • 如果MS决定增加最大列数
      • ,则字符串也可以提供更多维护
  • 将功能用于一个目的(就像您一样) - 以后不再包含其他功能
  • 该功能应该是自包含的
    • 能够检测并处理所有可能的错误和意外输入
    • 并生成最通用且可用的输出
  • 通过在此特定函数中返回0,期望有效数字的调用将在第0行中出错
    • 因此,即使工作表为空,您也可能希望将其更改为1
      • 并在呼叫返回后检查顶部单元格是否为空白

作为说明:

主文件中的几个工作簿

  • 工作簿是一个文件
  • 工作表是文件中的选项卡(文件可以包含多个工作表/选项卡)
  • 始终明确所有对象
    • Range("A" & Rows.Count).End(xlUp).Row隐式使用ActiveWorkbook.ActiveSheet
    • 转换为ActiveWorkbook.ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
    • 如果您需要使用多个工作簿和工作表,请完全符合您的来电条件
      • `工作簿(&#34; Book1&#34;)。工作表(&#34; Sheet3&#34;)。范​​围(&#34; A&#34;&amp; Rows.Count).End(xlUp)。行
      • `工作簿(&#34; Book2&#34;)。工作表(&#34; Sheet2&#34;)。范​​围(&#34; A&#34;&amp; Rows.Count).End(xlUp)。行
    • 因此Excel可以访问您需要使用的确切对象

如果使用完整引用,则代码不依赖于活动对象   - 如果用户激活不同的工作簿或工作表,代码将继续正常工作

希望这有帮助

PS。当使用行变量时,总是将它们声明为Long,以便能够处理超过32,767的整数 - 当前Excel最多有1,048,576行(​​将来这个最大值可以增加甚至更高)