学习Excel技术,关注微信公众号:
Excelperfect
当VBA代码运行过程中发生错误时,都会给Err对象的属性赋值,这样可以使用Err对象来查看错误的详细信息。在运行时发生错误,VBA会自动使用详细信息填充Err对象。
在上文中,我们已经在一些代码里使用过Err对象,显示错误号或错误描述。Err对象的Number属性返回错误号,Description属性返回相关的错误信息。
下面的代码给出“错误号: 13 类型不匹配”,因为试图在Long变量中存储字符串值。
Sub ErrDemo()
On Error GoTo errH
Dim i As Long
i = "aa"
Done:
Exit Sub
errH:
MsgBox "错误号: "& Err.Number _
& " " &Err.Description
End Sub
运行上述代码后的结果如下图10所示。
图10
Err.Description
提供发生错误的详细信息,这是通常在错误发生时看到的文本,例如上例中的“类型不匹配”。
当程序运行出现错误时,标准错误描述将自动赋值给Description属性。
也可以设置错误发生时的描述文本,例如Err.Description = “发生用户输入错误”。
为程序错误设置Description属性的最好方法是在Raise方法中设置Description参数值,例如代码:
Sub TestErrDes()
On Error GoTo errH
Err.Raise Number:=65300, _
Description:="发生用户输入错误"
Done:
Exit Sub
errH:
MsgBox Err.Description
End Sub
运行代码后的结果如下图11所示。
图11
Err.Number
返回错误的ID号,例如上例中“类型不匹配”的错误号是13。这可用于检查是否发生了特定错误。
在程序运行时产生错误时,错误号自动赋值给Err.Number。注意,使用Err.Number方法时,用户定义错误号不能大于65536和小于0。
下图12列出了一些错误代码及其含义。
图12
下面的代码判断指定的工作簿文件是否打开并显示相应的消息:
Sub CheckWBOpen()
Dim strFileName As String
Dim wb As Workbook
strFileName = "test.xlsx"
On Error Resume Next
Set wb = Workbooks(strFileName)
If Err.Number = 0 Then
MsgBox "工作簿"& strFileName & "已打开."
Else
MsgBox "工作簿"& strFileName & "未打开."
End If
End Sub
Err.Raise
允许创建错误,即产生一个运行时错误,可以使用它来创建自定义错误。其语法格式如下:
Err.Raise 错误号, [错误源], [错误描述], [帮助文件], [帮助内容]
注意,要使用Raise方法,必须指定错误号。并且,在将传递的参数赋值之前,Raise方法不会重新初始化Err对象,这意味着如果上一个错误产生后没有清除Err对象而又产生一个错误,那么那些没有指定属性值的属性仍然为上一个错误所对应的值。
看一个示例。假设想要确保单元格中输入内容恰好是5个字符,否则给出一个特定的消息。代码如下:
Public Const ERROR_INVALID_DATA As Long = vbObjectError + 513
Sub ReadWorksheet()
On Error GoTo errH
If Len(Sheet1.Range("A1"))<> 5 Then
Err.Raise ERROR_INVALID_DATA,"ReadWorksheet" _
, "在单元格A1中的值必须正好有5个字符."
End If
'如果单元格具有有效的数据则继续
Dim ID As String
ID = Sheet1.Range("A1")
Done:
Exit Sub
errH:
'Err.Raise发送代码到此
MsgBox "发现错误: "& Err.Description
End Sub
在使用Err.Raise创建错误时,需要为其提供一个错误号。可以使用513至65535之间的任何数字,必须使用vbObjectError加上数字:
vbObjectError+ 513
运行上述代码后的结果如下图13所示。
图13
Err.Clear
用于清除Err对象中的文本和数字。换句话说,它清除了错误描述和错误编号。
在下面的代码中,我们计算发生的错误数。为简单起见,我们为每个奇数生成一个错误。每次循环时,我们都会检查错误号。如果数字不等于零,则发生错误。一旦计算出错误,就需要将错误号设置回零,以便准备检查下一个错误。
Sub UsingErrClear()
Dim lCount As Long
Dim i As Long
'忽略错误,并检查错误号
On Error Resume Next
For i = 0 To 9
'每隔一个数字生成一个错误
If i Mod 2 = 1 Then Error (13)
'检查错误
If Err.Number <> 0 Then
lCount = lCount + 1
'计数后清除错误
Err.Clear
End If
Next
MsgBox "共发生错误数为: "& lCount
End Sub
运行上述代码的结果如下图14所示。
图14
通过设置Err.Number属性值为0能得到与使用Err.Clear方法相同的结果。
注意,Err.Clear只是重置错误对象中的文本和数字,但不能清除错误。
示例:错误日志
在发生错误时,可以将详细信息写入文本文件,以便记录错误。
下面的代码演示了一个非常简单的日志记录过程:
Sub LogRecord(strType As String, _
strSource As String, _
strDetails As String)
Dim strFilename As String
strFilename ="C:\temp\logging.txt"
'以某大小存档文件
If FileLen(strFilename) > 20000 Then
FileCopy strFilename _
, Replace(strFilename,".txt", Format(Now, "ddmmyyyy hhmmss.txt"))
Kill strFilename
End If
'打开文件来写入
Dim filenumber As Variant
filenumber = FreeFile
Open strFilename For Append As #filenumber
Print #filenumber, CStr(Now) &"," & _
strType & "," &strSource _
& "," & strDetails& "," _
& Application.UserName
Close #filenumber
End Sub
下面的代码来使用LogRecord过程:
Public Const ERROR_DATA_MISSING As Long = vbObjectError + 514
Sub CreateReport()
On Error GoTo errH
If Sheet1.Range("A1") ="" Then
Err.Raise ERROR_DATA_MISSING,"CreateReport", "单元格A1数据丢失"
End If
'这里放置其它代码
Done:
Exit Sub
errH:
LogRecord "错误",Err.Source, Err.Description
End Sub
如果工作表Sheet1中单元格A1为空,则运行上述代码后生成的错误日志如下图15所示。
图15
这个日志不仅记录错误,也可以在应用程序运行时记录其他信息。发生错误时,可以检查错误发生之前的事件顺序。
处理错误时,拥有大量信息可能非常有用。用户通常可能不会向你提供有关所发生错误的准确信息。通过查看日志,你可以获得有关错误的更准确的信息。