无法引用工作表代码名称

时间:2014-10-12 01:37:44

标签: excel excel-vba excel-2013 vba

这是基本问题:我正在编写一个Excel宏,我想使用工作表代码名称来尝试消除任何错误。我可以使用Sheet1的代码名称,它工作正常,但当我尝试使用其他代码,如Sheet3或Sheet7时,编辑器无法识别它们,如果我运行宏Excel,则会出现错误,告诉我我的“变量未定义“。

例如:

Option Explicit

Sub Test()

Dim SheetObject As Worksheet
Dim SheetObject2 As Worksheet

Set SheetObject = Sheet1
Set SheetObject2 = Sheet3

MsgBox (SheetObject.Name)
MsgBox (SheetObject2.Name)


End Sub

如果我注释掉任何引用SheetObject2的代码,宏就会正确运行。如果我把它们放入,我会得到错误。我肯定有一个Sheet3,代码名称肯定是Sheet3。我整天都在环顾谷歌,似乎无法提出任何解决方案,任何帮助都会很棒。

提前致谢,

杰西

1 个答案:

答案 0 :(得分:1)

我的上一位雇主收集了数据并创建了国家统计数据。大部分数据以Excel工作簿的形式出现,因此我有很多相关经验。

如果你正在运行自己的宏,如果这是一次性练习,那么这样的测试可能就足够了:

Debug.Assert WbookTgt.WsheetTgt.Range("A1").Value = "Date"

许多语言都有 Assert语句作为开发辅助工具;这是VBA版本。如果断言不为真,则宏将停止并突出显示此语句。

如果这种方法不充分,您应该考虑开发执行检查和更新任务的参数化宏。我查看了一些旧的宏,但大多数人都不会对VBA新手有所了解。我已经提取了代码来创建两个宏,我希望能给你一些想法。

宏1 - OpenWorkbook

定期提供数据的组织通常使用以下名称:" Xxxxx 1409.xlsx"和" Xxxxx 1410.xlsx"他们的数据的9月和10月版本。例如,您可以每月更新宏以获取最新名称,或者您可以将文件名更改为标准值。这些可能性中的任何一种都是令人讨厌的,我会特别反对第二个想法,因为我喜欢存档我处理过的所有工作簿。

OpenWorkbook()使用Dir语句在文件夹中搜索与模板匹配的文件,例如“Xxxxx * .xls *”。如果单个文件与此模板匹配,则宏将打开工作簿并返回对它的引用。

宏2 - CheckWorksheets

您可能已经注意到某些VBA例程具有固定数量的参数,而其他VBA例程具有可变数量的参数。例如,以下是CheckWorksheets的所有有效调用:

If CheckWorksheets(WbookTgt, WbookThis, “Name1”) then
If CheckWorksheets(WbookTgt, WbookThis, “Name1”, “Name2”) then
If CheckWorksheets(WbookTgt, WbookThis, “Name1”, “Name2”, “Name3”) then

CheckWorksheets有三个参数。前两个是工作簿参考。第三个是ParamArray SheetName() As Variant。前两个之后的任何参数都放在数组SheetName中,该数组可以根据需要大小。这里所有尾随参数都是字符串,但它们可以是任何类型。

我可以使用OpenWorkbook打开本月的源文件版本,然后使用CheckWorksheets确认我的宏所需的所有工作表。

工作表错误“

这两个宏需要工作表错误存在于指定的工作簿中。如果宏检测到错误,则会向此工作表添加详细的错误消息。我发现这是捕获任何错误细节的便捷技术。

宏Demo1和Demo2

我已经包含了两个宏,它们演示了如何在我的系统上使用这些宏和工作簿。如果你修改Demo1和Demo2来操作你的某些工作簿,你应该知道OpenWorkbook和CheckWorksheets可以为你做什么。

尽可能回答问题,但是你自己解读OpenWorkbook和CheckWorksheets的次数越多,你发展自己技能的速度就越快

Option Explicit
Sub Demo1()

  Dim Path As String
  Dim WbookThis As Workbook
  Dim WbookTgt As Workbook

  ' Application.ThisWorkbook identifies the workbook containing this macro.
  Set WbookThis = Application.ThisWorkbook

  ' I find it convenient to place my target workbooks in the folder
  ' holding the workbook containing the macro(s).
  Path = WbookThis.Path

  Set WbookTgt = OpenWorkbook(Path, "Combined*.xls*", WbookThis)

  If WbookTgt Is Nothing Then
    ' Detailed error message already recorded in "Errors"
    Call MsgBox("Wokbook failed checks", vbOKOnly)
  Else
    With WbookTgt
      Debug.Print .Path & "\" & .Name & " opened."
      .Close SaveChanges:=False
    End With
  End If

End Sub
Sub Demo2()

  Dim Path As String
  Dim WbookThis As Workbook
  Dim WbookTgt As Workbook

  ' Application.ThisWorkbook identifies the workbook containing this macro.
  Set WbookThis = Application.ThisWorkbook

  ' I find it convenient to place my target workbooks in the folder
  ' holding the workbook containing the macro(s).
  Path = WbookThis.Path

  Set WbookTgt = OpenWorkbook(Path, "Combined 2.04.xls*", WbookThis)

  If WbookTgt Is Nothing Then
    ' Detailed error message already recorded in "Errors"
    Call MsgBox("Wokbook failed checks", vbOKOnly)
    Exit Sub
  End If
  With WbookTgt
    If Not CheckWorksheets(WbookTgt, WbookThis, "Critical Path", "Dyn Dims") Then
      Call MsgBox("Wokbook failed checks", vbOKOnly)
      .Close SaveChanges:=False
      Exit Sub
    End If
    Debug.Print .Path & "\" & .Name & " contains worksheets Critical and Dym Dims"
    .Close SaveChanges:=False
  End With

End Sub
Function CheckWorksheets(ByRef WbookTgt As Workbook, ByRef WbookError As Workbook, _
                         ParamArray SheetName() As Variant) As Boolean

  ' * Return True if WbookTgt contains every specified worksheet.

  ' * WbookTgt is the workbook to be checked
  ' * WbookError identifies the workbook containing worksheet "Error" to which any
  '   error message will be added.
  ' * SheetName() is an array of worksheet names.

  Dim ErrorMsg As String
  Dim FoundError As Boolean
  Dim FoundSheet() As Boolean
  Dim FoundSheetsCount As Long
  Dim InxName As Long
  Dim InxWsheet As Long
  Dim NotFoundSheetsCount As Long
  Dim RowErrorNext As Long
  Dim SheetNamesFound As String

  ' Size FoundSheet to match SheetName.  Array elements initialised to False
  ReDim FoundSheet(LBound(SheetName) To UBound(SheetName))

  FoundSheetsCount = 0
  NotFoundSheetsCount = 0
  With WbookTgt
    For InxName = LBound(SheetName) To UBound(SheetName)
      NotFoundSheetsCount = NotFoundSheetsCount + 1   ' Assume not found until found
      For InxWsheet = 1 To .Worksheets.Count
        If SheetName(InxName) = .Worksheets(InxWsheet).Name Then
          FoundSheet(InxName) = True
          FoundSheetsCount = FoundSheetsCount + 1
          NotFoundSheetsCount = NotFoundSheetsCount - 1
          Exit For
        End If
      Next
    Next
  End With

  If NotFoundSheetsCount = 0 Then
    CheckWorksheets = True
    Exit Function
  End If

  SheetNamesFound = ""
  ErrorMsg = WbookTgt.Path & "\" & WbookTgt.Name & " does not contain "
  If NotFoundSheetsCount = 1 Then
    ErrorMsg = ErrorMsg & "this expected worksheet:"
  Else
    ErrorMsg = ErrorMsg & "these expected worksheets:"
  End If
  For InxName = LBound(SheetName) To UBound(SheetName)
    If Not FoundSheet(InxName) Then
      ErrorMsg = ErrorMsg & vbLf & "  " & SheetName(InxName)
    Else
      SheetNamesFound = SheetNamesFound & vbLf & "  " & SheetName(InxName)
    End If
  Next
  If FoundSheetsCount = 0 Then
    ' No need to add list of found sheet names
  Else
    ErrorMsg = ErrorMsg & vbLf & "but does contain "
    If FoundSheetsCount = 1 Then
      ErrorMsg = ErrorMsg & "this expected worksheet:"
    Else
      ErrorMsg = ErrorMsg & "these expected worksheets:"
    End If
    ErrorMsg = ErrorMsg & SheetNamesFound
  End If
  With WbookError
    With .Worksheets("Errors")
      RowErrorNext = .Cells(Rows.Count, "A").End(xlUp).Row + 1
      With .Cells(RowErrorNext, "A")
        .Value = Now()
        .VerticalAlignment = xlTop
      End With
      .Cells(RowErrorNext, "B").Value = ErrorMsg
    End With
  End With
  CheckWorksheets = False

End Function
Function OpenWorkbook(ByVal Path As String, ByVal FileTemplate As String, _
                      ByRef WbookError As Workbook) As Workbook

  ' * If Path & FileTemplate identifies a single workbook, open it and return
  '   it as an object.  If Path & FileTemplate does not represent a single
  '   workbook, report the problem in worksheet Errors and return Nothing.

  ' * WbookError identifies the workbook containing worksheet "Error".
  ' * Path must be the name of the folder in which the required workbook is located
  ' * FileTemplate can either be a specific filename or can contain wild cards
  '   providing only one file matches the template.
  ' * WbookError identifies the workbook containing worksheet "Error" to which any
  '   error message will be added.

  Dim ErrorMsg As String
  Dim FileNameCrnt As String
  Dim FileNameMatch As String
  Dim RowErrorNext As Long

  FileNameMatch = Dir$(Path & "\" & FileTemplate, vbNormal)
  If FileNameMatch = "" Then
    ' No matches found
    ErrorMsg = "Template " & Path & "\" & FileTemplate & " does not match any file"
  Else
    ' At least one match.
    ' If only one match, its name is in FileNameMatch
    Do While True
      FileNameCrnt = Dir$
      If FileNameCrnt = "" Then
        ' No more matches
        Exit Do
      End If
      ' A second or subsequent match has been found.
      If FileNameMatch <> "" Then
        ' This is the second match.
        ' Initialise error message and report name of first match
        ErrorMsg = "Template " & Path & "\" & FileTemplate & " matches more than one file:" & _
                   vbLf & "  " & FileNameMatch
        FileNameMatch = ""      ' No single match
      End If
      ' Add name of current match to error message
      ErrorMsg = ErrorMsg & vbLf & "  " & FileNameCrnt
    Loop
  End If

  If FileNameMatch = "" Then
    ' No single match found.
    ' ErrorMsg contains an appropriate error message
    With WbookError
      With .Worksheets("Errors")
        RowErrorNext = .Cells(Rows.Count, "A").End(xlUp).Row + 1
        With .Cells(RowErrorNext, "A")
          .Value = Now()
          .VerticalAlignment = xlTop
        End With
        .Cells(RowErrorNext, "B").Value = ErrorMsg
        Set OpenWorkbook = Nothing
      End With
    End With
  Else
    ' Single match found
    Set OpenWorkbook = Workbooks.Open(Path & "\" & FileNameMatch)
  End If

End Function

对额外问题的回应

VBA没有VB Try那么方便,但它在程序员控制下确实有一些错误处理。

如果使用如下命令:

Worksheets("Sheet2").Delete

将要求用户确认删除。为避免这种情况,请使用:

Application.DisplayAlerts = False
Worksheets("Sheet2").Delete
Application.DisplayAlerts = True

我在宏的开头看到了带有Application.DisplayAlerts = False的代码,这意味着即使编程人员没有预料到,也不会显示用户注意的警报。通过将Delete括起来,我确保只会抑制我所期待的警报。

考虑:

Sub OpenFile()
  Dim InputFileNum As Long
  InputFileNum = FreeFile
  Open "Dummy.txt" For Input As InputFileNum
  Debug.Print "File successfully opened"
  Close InputFileNum
End Sub

文件&#34; Dummy.txt&#34;不存在,因此宏将停在Open语句上。

您有时会看到这样的代码:

Sub OpenFile()

  Dim InputFileNum As Long

  On Error GoTo ErrorCode

  InputFileNum = FreeFile
  Open "Dummy.txt" For Input As InputFileNum
  Call MsgBox("File successfully opened", vbOKOnly)
  Close InputFileNum
  Exit Sub

ErrorCode:
  Debug.Print "Unexpected error: " & Err.Number & " " & Err.Description

End Sub

这里我提供了可能发生的任何错误情况的通用处理程序。我不赞成,虽然我接受这比非技术用户看到错误陈述突出显示要好一些。麻烦是任何错误都会导致同样无用的错误消息。

我从不在开发过程中包含错误处理。如果发生错误,我希望宏停止在错误的语句上,以便我可以考虑如何避免错误。在尝试打开文件之前,我应该检查文件是否存在。我更喜欢这样的东西:

Sub OpenFile()

  Dim FileSysObj As Object
  Dim InputFileNum As Long

  On Error GoTo ErrorCode

  Set FileSysObj = CreateObject("Scripting.FileSystemObject")

  If Not FileSysObj.FileExists("Dummy.txt") Then
    Call MsgBox("I am unable to find ""Dummy.txt"".  List of helpful suggestions.", vbOKOnly)
    Exit Sub
  End If

  InputFileNum = FreeFile
  Open "Dummy.txt" For Input As InputFileNum
  Call MsgBox("File successfully opened", vbOKOnly)
  Close InputFileNum
  Exit Sub

ErrorCode:
  Debug.Print "Unexpected error: " & Err.Number & " " & Err.Description

End Sub

我已经包含检查我期望的错误的代码。如果该文件不存在,我会显示一条消息,希望能帮助用户自行解决问题。

有时你无法避免错误。为了测试下面的代码,我创建了文件Dummy.txt但是设置了#34;读访问被拒绝&#34;旗。对于VBA宏来说,没有简单的方法(据我所知)来测试这个标志。我有一个意外错误的通用处理程序,但是我将其关闭为Open语句,因此我可以包含打开失败的特定代码。我删除了使用FileExists()来测试Dummy.txt是否存在的代码,因为更容易将其与其他打开文件错误测试一起包含。

Sub OpenFile()

  Dim FileSysObj As Object
  Dim InputFileNum As Long

  On Error GoTo ErrorCode       ' General handler for unexpected errors

  InputFileNum = FreeFile
  Err.Clear
  On Error Resume Next          ' Record error in Err object and continue
  Open "Dummy.txt" For Input As InputFileNum
  Select Case Err.Number
    Case 0
      ' No error.
    Case 53           ' File does not exist
      Call MsgBox("I am unable to find ""Dummy.txt"".  List of helpful suggestions.", vbOKOnly)
      Exit Sub
    Case 75           ' Path/File access error
      Call MsgBox("It appears file ""Dummy.txt"" exists but I do not have permission to read it.", vbOKOnly)
      Exit Sub
    Case Else
      Call MsgBox("My attempt to open ""Dummy.txt"" failed with an unexpected error condition" & vbLf & _
                  "  " & Err.Number & " " & Err.Description, vbOKOnly)
      Exit Sub
  End Select

  On Error GoTo ErrorCode      ' Restore general handler for unexpected errors

  Call MsgBox("File successfully opened", vbOKOnly)
  Close InputFileNum
  Exit Sub

ErrorCode:
  Debug.Print "Unexpected error: " & Err.Number & " " & Err.Description

End Sub

访问http://support.microsoft.com/kb/146864以获取一长串错误代码以及有关错误处理的更多信息。