2014-10-12 70 views
1

这里的基本问题:我正在写一个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。我整天环顾Google,似乎无法提出任何解决方案,任何帮助都会很棒。

由于提前,

杰西

+0

您确定'Sheet3'是实际的表单代码名称吗?试着循环遍历每一张表格并打印真实的代码名称,看看它们是否匹配,如下所示:'For Each wks In Worksheets Debug.Print wks.CodeName Next wks'或者试试像这样使用名称:'Set SheetObject2 = Worksheets (“Sheet3”)' – 2014-10-12 02:44:06

+0

试试这个:'For i = 1 To Worksheets.Count Debug.Print“sheet name =”&Worksheets(i).Name&vbCr _ &“code name =”&Worksheets(i) .CodeName&vbCr Next' – ZAT 2014-10-12 06:02:08

+0

'Set SheetObject = Sheets(1)',或'Set SheetObject = Sheets(“Sheet1”)',都可以,第一个是索引,第一个是它的名字。 – 2014-10-12 16:24:50

回答

1

我最后的用人单位收集数据和创建国家统计。大部分数据都是以Excel工作簿的形式出现的,所以我有很多相关的经验。

如果您运行的是自己的宏,如果这是一个一次性的练习,然后像这样的测试可能就足够了:

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

许多语言有一个断言语句作为发展援助;这是VBA版本。如果断言不成立,宏将停止并突出显示此语句。

如果这种做法是不足够的,你应该考虑制定参数化宏进行检查和更新任务。我已经浏览了一些旧的宏,但大多数人不会理解VBA新手。我已经提取代码来创建两个宏,我希望能给你一些想法。

宏1 - OpenWorkbook

组织,定期提供数据经常使用的名称类似:“XXXXX 1409.xlsx”和“XXXXX 1410.xlsx”为自己的数据的九月和十月的版本。例如,您可以每月更新宏以获取最新名称,或者可以将文件名更改为标准值。这两种可能性都是麻烦的,我会特别反对第二种想法,因为我喜欢将我所处理的所有工作簿存档。

OpenWorkbook()使用Dir语句来搜索文件夹,一个模板,如“XXXXX的* .xls *”相匹配的文件。如果单个文件与此模板匹配,宏将打开工作簿并返回对其的引用。

宏2 - CheckWorksheets

您可能已经注意到,一些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 

我曾在一个宏,这意味着任何警报将显示,即使pogrammer没想到它的用户的关注开始看到有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 

文件 “Dummy.txt” 不存在这样的宏将停止在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,但设置了“读访问被拒绝”标志。 (据我所知),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

+0

非常感谢Tony提供的这些示例,我通过它们进行了工作,并且我相信我对如何实现基于您的代码类型非常了不起,它可以满足我的特殊需求。在阅读完所有内容后,唯一的问题是:VBA中是否存在错误捕获代码?例如,VB.net使用Try ... Catch,在VBA中是否存在等价物或者是为错误编程捕捉错误的唯一方法?这可能超出了原始问题的范围,请随时将我指向另一个地方! – 2014-10-16 02:05:46

+0

我不确定提问者是否被告知是否修改了答案。这个评论是为了确保你被告知。 – 2014-10-16 10:29:01

+0

你在哪个时区?你的帖子在我的时间凌晨3点。 – 2014-10-16 10:30:23