疑难5 如何开发完善的程序
编写代码解决一个工作问题是很简单的,但是如何让程序完善,可以适应所有的环境,且通用、兼容、可防错,这是一门相当复杂的学问。那么如何开发一个完善的程序?如何及时地防止过程中的所有错误呢?
解决方案
通过常规思路开发一段程序完成基本需求,然后查找存在的问题并进行完善;再对新的过程审核是否有新问题,继续完善,直到代码可以应对一切外部环境。
本节以“让用户从对话框输入一个值,并对该值开平方后写入活动单元格”为例,展示利用VBA解决此问题且逐步完善程序的过程。
操作方法
步骤1 按组合键打开VBE窗口,然后插入模块,并在模块中录入以下代码:
Sub 获取平方根1 ''第一次编写的代码,直接解决问题
Dim Value As Long ''声明一个Long型变量
''让用户录入一个值,将该值赋予变量Value
Value = InputBox""请输入数值:"", ""待开方之数值"", 0
ActiveCell.Value = SqrValue ''对变量计算平方根
End Sub
步骤2 按键执行以上过程,并输入100或者789、123.455等数据进行测试,可以发现当前代码已实现需求的功能。然而,如果用户在对话框中单击“取消”按钮,那么程序会出错。用户很难通过出错提示了解出错的原因,而且假设后面还有其他代码,程序将不再执行。为了解决以上问题,修改代码为:
Sub 获取平方根2 ''解问按“取消”键问题
Dim Value As Variant
Value = InputBox""请输入数值:"", ""待开方之数值"", 0
If LenValue = 0 Then Exit Sub ''如果变量的值长度为0,那么结束过程,不弹 ''出错误提示
ActiveCell.Value = SqrValue
End Sub
步骤3 再次执行程序,单击“取消”按钮后会发现程序自动退出,不弹出错误提示,具有防错功能。也可以将“Exit sub”语句修改为其他代码,从而实现单击“取消”按钮后程序得以继续执行。
不过当输入一个负数时,程序仍然会出错,且自动中断,因此需要继续改进代码。改进后的代码如下:
Sub 获取平方根3 ''解决负数问题
Dim Value
Value = InputBox""请输入数值:"", ""待开方之数值"", 0
If LenValue = 0 Then Exit Sub ''如果变量的值长度为0,那么结束过程,不弹 ''出错误提示
''若变量Value的值大于或等于0,则对变量开平方,且将结果存放在活动单元格,否则提示用户
If Value = 0 Then ActiveCell.Value = SqrValue Else MsgBox ""不能小于0""
End Sub
步骤4 当输入负数后,程序会提示用户且自动结束过程,但如果用户输入文本,那么程序仍然会出错,所以再次对代码做优化:
Sub 获取平方根4 ''解决文本问题
Dim Value
Value = InputBox""请输入数值:"", ""待开方之数值"", 0
If LenValue = 0 Then Exit Sub ''如果变量的值长度为0,那么结束过程,不''弹出错误提示
If IsNumericValue Then ''如果变量Value的值是数值
''若变量Value的值大于或等于0,则对变量开平方,且将结果存放在活动单元格,否则提示用户
If Value = 0 Then ActiveCell.Value = SqrValue Else MsgBox ""不能小于0""
Else ''否则,提示不能输入文本
MsgBox ""不能输入文本"", 64, ""提示""
End If
End Sub
步骤5 如果输入文本,程序具有了识别并警告用户的功能。然而,活动表是图表时,执行程序时仍然会出错。完善的程序需要处理所有的意外,那么程序可以做如下改进:
Sub 获取平方根5 ''解决图表问题
Dim Value
''如果活动表是图表,那么提示用户,而且结束过程
If TypeNameActiveSheet = ""Chart"" Then MsgBox ""不要选择图表"": Exit Sub
Value = InputBox""请输入数值:"", ""待开方之数值"", 0
If LenValue = 0 Then Exit Sub ''如果变量的值长度为0,那么结束过程,不''弹出错误提示
If IsNumericValue Then ''如果变量Value的值是数值
''若变量Value的值大于或等于0,则对变量开平方,且将结果存放在活动单元格,否则提示用户
If Value = 0 Then ActiveCell.Value = SqrValue Else MsgBox ""不能小于0""
Else ''否则,提示不能输入文本
MsgBox ""不能输入文本"", 64, ""提示""
End If
End Sub
步骤6 如果工作表在被保护状态下执行以上程序仍然会出错,继续完善代码:
Sub 获取平方根6 ''解决工作表保护问题
Dim Value
''如果活动表是图表,那么提示用户,而且结束过程
If TypeNameActiveSheet = ""Chart"" Then MsgBox ""不要选择图表"": Exit Sub
''如果活动表处于保护状态,那么提示用户,然后结束过程
If ActiveSheet.ProtectContents Then MsgBox ""工作表已保护"": Exit Sub
Value = InputBox""请输入数值:"", ""待开方之数值"", 0
If LenValue = 0 Then Exit Sub ''如果变量的值长度为0,那么结束过程,不''弹出错误提示
If IsNumericValue Then ''如果变量Value的值是数值
''若变量Value的值大于或等于0,那么对变量开平方,且将结果存放在活动单元格,否则提示用户
If Value = 0 Then ActiveCell.Value = SqrValue Else MsgBox ""不能小于0""
Else ''否则,提示不能输入文本
MsgBox ""不能输入文本"", 64, ""提示""
End If
End Sub
步骤7 如果活动单元格处于数组区域之间,程序仍然会产生错误,所以最后将代码优化为:
Sub 获取平方根7 ''解决数组区域问题
Dim Value
''如果活动表是图表,那么提示用户,而且结束过程
If TypeNameActiveSheet = ""Chart"" Then MsgBox ""不要选择图表"": Exit Sub
''如果活动表处于保护状态,那么提示用户,然后结束过程
If ActiveSheet.ProtectContents Then MsgBox ""工作表已保护"": Exit Sub
Value = InputBox""请输入数值:"", ""待开方之数值"", 0
If LenValue = 0 Then Exit Sub ''如果变量的值长度为0,那么结束过程,不''弹出错误提示
If IsNumericValue Then ''如果变量Value的值是数值
On Error Resume Next ''如果代码出错,继续执行下一步
Debug.Print ActiveCell.CurrentArray ''将活动单元格的当前数据区域地址输''出到立即窗口
''如果没有错误表示处于数组区域中,那么提示用户,然后结束过程
If Err = 0 Then MsgBox ""请不要选择数组区域"": Exit Sub
''若变量Value的值大于或等于0,则对变量开平方,且将结果存放在活动单元格,否则提示用户
If Value = 0 Then ActiveCell.Value = SqrValue Else MsgBox ""不能小于0""
Else ''否则,提示不能输入文本
MsgBox ""不能输入文本"", 64, ""提示""
End If
End Sub
原理分析
编程的基本条件是准确性。然而程序除了准确以外,还必须具备防错和通用的特性,否则代码在当前状态下能正确执行,环境稍加变化就出现错误,将会增加维护成本。一个好的程序应该尽量通用于所有的状况,而本例正是通过一个典范来展示程序的完善过程,让读者了解程序可能出现的错误,并提供所有错误的解决之道。在实际工作中,都应该严格按此思路编写代码,提升程序的准确性、纠错性,同时也减少维护成本。
知识扩展
数组区域对VBA程序的影响
(1)区域数组公式是同时存在于多个连续单元格中带有“{}”标志的公式,将它输入到工作表后会占据一个区域的空间,而非单个单元格,该区域即为数组区域。它的特性是不能单独修改区域中任意一个单元格,如果代码修改其中一个单元格,程序会因出错而中断。
(2)本例其实也可以利用“On Error Resume Next”语句一次性解决所有的问题,其代码如下。不过如果执行程序后得不到结果,就无法知道出错的原因。
Sub 获取平方根8 ''解决所有的问题
On Error Resume Next
ActiveCell.Value = SqrApplication.InputBox""请输入数值:"", ""开平方"", 0, , , , , 1
End Sub
注意
本书中编程的主题是准确性、效率、防错性和兼容性,代码一定要对所有的错误进行防范,确保程序通用。然而为了节约篇幅,让书中展现更多的内容,我们尽量减少重复代码,对工作表是否保护、当前表是否为图表,以及活动单元格是否处于数组区域之间就不再对每个案例都进行判断了,