ad

连代码调试都一窍不通,还谈啥会VBA?-英雄云拓展知识分享

匿名投稿 238 2024-01-30

有句俗语说的好,一段优秀的代码,3分靠编写7分靠调试。今天我就给大家聊一下VBA代码调试的问题:一段代码写完了,运算结果却不对,到底应当如何发现并改正毛病?

本章概要以下:

连代码调试都一窍不通,还谈啥会VBA?-英雄云拓展知识分享

❶ 语法检查
❷ 逻辑检查
❸ 样本调式
❹ 运行调试

❺ 毛病处理

 

1、语法毛病

对新手而言,早期编写的VBA代码其实不会有复杂的逻辑,最多见的毛病就是语法毛病。

典型有以下3种。

1) 声明对象变量,漏了关键字Set。
Sub t()
Dim sht As Worksheet
sht = Worksheets(1)
MsgBox sht.Name

End Sub

以上代码第3即将第1个工作表赋值变量sht,但由于并未使用关键字Set,代码会返回下图所示的毛病信息:对象变量或with块变量未设置。

正确代码以下:

Sub t()
Dim sht As Worksheet
Set sht = Worksheets(1)
MsgBox sht.Name

End Sub

2)循环或判断语句不完全。

当有多层循环语句或条件判断语句嵌套时,新手朋友容易遗漏Next或End If语句。需要注意的是,当If语句嵌套在循环语句中时,如果缺少End If,系统会提示”编译毛病,Next没有For”。这提示张冠李戴的不要太明显。

以下代码缺失End If语句。

Sub t3()
Dim sht As Worksheet
For Each sht In Worksheets
If sht.Name = "看见星光" Then
If sht.Cells(1, 1) = "excel" Then
MsgBox "对"
'这里少了End If 你发现了吗,我们将继续深入。
Next

End Sub

运行后提示毛病以下:

解决此类毛病,最好是养成代码缩进与提早输入结构语句的习惯。关于代码缩进的规则,VBA系列教程里有详细的讲述,这里不再啰嗦。而输入结构语句是指…
写了For语句后,立刻空两行写Next语句,再在循环体中编写其它语句。
For Each sht In Worksheets

Next
写了If语句后,也空两行写End If语句。
If sht.Name = "看见星光" Then

End If

3)工作表对象缺失

这个毛病基本上每一个VBA学员都遇见。
有段代码以下:

代码看不全可以左右滑动…

Sub t4()
Dim arr
arr = Worksheets(1).Range("a1:b" & Cells(Rows.Count, 1).End(xlUp).Row)

End Sub

第3行代码将第1个工作表的A:B列数据区域赋值数组arr。其中
Cells(Rows.Count, 1).End(xlUp).Row部份,
本意是返回Worksheets(1)第1列最后一个存在数据的单元格的行号,这代码看起来仿佛正常无误。

但是,我们在VBA教程里讲过,如果单元格前未指定工作表对象,则默许为当前活开工作表——当前活开工作表,未必就是Worksheets(1),代码运行后,arr数组也就未必会返回正确的结果。

正确代码参考以下:

Sub t4()
Dim arr
With Worksheets(1)
arr = .Range("a1:b" & .Cells(Rows.Count, 1).End(xlUp).Row)
End With

End Sub

注意Cells前有个.代表With所援用的Worksheets(1)对象。

 

2、逻辑毛病

相比于语法毛病,麻烦的是逻辑毛病。
代码运算的逻辑,有些来源于数据分析与处理的基本逻辑,有些来源于公司的业务逻辑。对后者,常常只有行业内的人材能经过你的描写快捷理解。
这时候就有可能产生这样的情形:有的朋友发出来一段代码,也不说运算逻辑,就问为何代码运行后不提示毛病,但结果其实不对……

坦白的说,这类行动就给有人问为何输入公式1+1不提示毛病,但结果也不等于料想的3,差不了多少——就让人很无语。

如何梳理逻辑毛病呢?
首先,正如我们一直突出的,所谓编程,就是顺序、分支和循环。顺序就是运算的前后顺序,分支就是运算的条件层次,循环就是遍历数据,所以请养成做思惟导图的习惯,经过思惟导图梳理清楚代码运算的顺序和条件层次——相信我,这非常有助于你快捷而准确的编写代码。

然后,在代码中尽可能增加注释。注释的好处我们在VBA系列教程中编写VBA代码有哪些注意事项里有详细解释,像我这么傲骄的人,这里不再重复,你晓得图片。

最后,请继续往下看(*^▽^*)

 

3、样本调试

不论是检查代码的语法毛病还是逻辑毛病,都离不开样本调试;也就是用一个样本数据逐渐运行代码,发现并修正毛病。上面这句话包括了两个重点辞汇:样本数据、逐渐运行。

样本数据要求小而全。

小是指数据量必须小,比如,你需要从如上图所示的10万行数据中查找A列包括关键字”上海”、”福建”、”广东”,同时B列性别等于男的结果表,你不能拿10万个数据一个一个去测试,这样你不是风儿也是沙;事实上,有3条左右的样本数据就足够了。

全是指数据的代表性需全面,仍然以上图所示数据为例,C列的性别就不能只有男的,没有女的,固然,也不能只有女的,没有男的。

参考代码以下:

Sub t()
Dim aData, aRes, aRef, s
Dim i As Long, j As Long, k As Long
aData = Worksheets("数据源").Range("a1").CurrentRegion
ReDim aRes(1 To UBound(aData), 1 To UBound(aData, 2))
aRef = Array("上海", "福建", "广东")
For i = 1 To UBound(aData)
If aData(i, 3) = "男" Then '判断性别是不是为男
For Each s In aRef '判断是不是包括城市关键字
If InStr(aData(i, 1), s) Then
k = k + 1
For j = 1 To UBound(aData, 2)
aRes(k, j) = aData(i, j)
Next
Exit For '退出循环
End If
Next
End If
Next
Worksheets("结果表").Select
Cells.ClearContents
Range("a1").Resize(1, UBound(aData, 2)) = aData '读取标题
Range("a2").Resize(k, UBound(aRes, 2)) = aRes
MsgBox "ok"

End Sub

 

4、代码调试

重点说一下代码逐渐调试,这包括了逐语句调试、断点调试等情况。

逐语句调试是指以语句为单位分步运行代码。按一次键,VBA将运行当前进程,然后高亮显示下一个语句并进入中断模式。按屡次键,便可逐语句运行代码。

当代码逐语句运行时,我们可以经过本地窗口,实时查看变量内容是不是符合计算预设。

断点调试就是在程序中设置代码暂时停止运行的位置,这个位置被称为断点。当代码运行到断点所在的语句时,程序会进入中断模式,同时高亮显示断点代码行。

设置断点最经常使用的方法是将鼠标指针悬停在【代码窗口】左边灰色区域内,当鼠标指针显示为指向左上方的箭头时,单击便可设置该代码行动断点。

断点设置完成后,会出现一个红色大圆点,单击该断点标识,便可删除断点。

断点可以存在多个,如果存在断点,按键后,VBA将运行代码直至断点处进入中断模式。此时,经过本地窗口,或搭配运行MsgBox语句,可以查看代码中的变量值是不是运行有误。

除此以外,使用Stop语句也能够实现断点调试的效果。

以上述代码为例,如果需要查看变量K的累加进程,可以在语句k=k+1后添加一行Stop语句,代码运行到Stop语句时将自动进入中断模式,再经过本地窗口,便可查看相干变量的数据。

不论是逐语句调试还是断点调试,都是为了查看代码的运算进程,和变量的值是不是正确。
查看变量优先推荐使用本地窗口,但有时候本地窗口的变量过量,如果只是查看个别变量,使用起来就不是很方便,相比之下,使用Msgbox语句更加适合。

以上述案例为例,如果需要查看第1条符合查询规则的行号,可以在If判断语句后增加以下两行代码。


MsgBox i
Stop

….

代码运行后返回结果以下图所示。

本地窗口和Msgbox语句都是显示某个运算环境下的特定值,如果需要查看特定变量在全部进程中的全部值,可使用Debug对象的Print方法,该方法可以在【立即窗口】打印不同类型的数据。
还是举个例子。

在第10行If语句后,增加一行Debug.Print (i)语句,然后运行进程,可以在立即窗口查看所有符合条件的所有行号。

Debug.Print 比较经常使用的一个情形是测试不同代码的运行速度。

以下代码测试了将10000个数据写入工作表的两类方式的时间差异,这两类方式一个是逐一单元格写入,另外一个是数组批量写入。

Sub t2()
Dim i As Long, arr, t
t = Timer
For i = 1 To 10000 '在1万个单元格中写入数据
Cells(i, 1) = i
Next
Debug.Print ("逐一单元格写入的时间是:" & Timer - t)
t = Timer
ReDim arr(1 To 10000, 1 To 1)
For i = 1 To 10000
arr(i, 1) = i
Next
Range("b1:b" & UBound(arr)) = arr
Debug.Print ("数组写入的时间是:" & Timer - t)

End Sub

运行代码后结果以下图所示:

最后需要补充说明两点:

1)当进程重复运行时,立即窗口的内容其实不会自动清除。

2)除将变量数据写入立即窗口,也能够将其写入工作表中,二者各有优劣,看个人习惯和实际需求。

 

5、毛病处理

不管你如何认真的编写代码,程序运行时依然有可能出现毛病,这或许会让初学编程的你感到困惑,但从某种角度来讲,毛病确切是程序不可或缺的一部份,所以请躺平微笑面对毛病,并坚定不移的抱有3种态度:忽视它、捕捉它、反馈它。

使用On Error Resume Next语句,可以忽视程序中的毛病,继续运行毛病语句后的代码。

以下代码删除名称为”数据”的工作表。为了避免工作簿不存在相干名称的工作表,造成第4行删除工作表的代码运行毛病,第3行代码使用容错语句。

Sub t3()
On Error Resume Next
Application.DisplayAlerts = False
Worksheets("数据").Delete
MsgBox "名称为数据的工作表已删除"
Application.DisplayAlerts = True

End Sub

捕捉和反馈毛病可使用Err对象。

举个例子,还是删除名称为”数据”的工作表,示例代码以下:

Sub t4()
Dim d As Object
Application.DisplayAlerts = False
Set d = CreateObject("scripting.dictionary") '演示释放变量
On Error GoTo ErrHander
Worksheets("数据").Delete
MsgBox "名称为数据的工作表已删除"
Application.DisplayAlerts = True
errExit:
Set d = Nothing
Exit Sub
ErrHander:
MsgBox "程序产生毛病。" & vbCrLf & _
"毛病编号:" & Err.Number & vbCrLf & _
"毛病内容:" & Err.Description
Resume errExit

End Sub

第5行代码是On Error GoTo line语句。它可以跳转到指定的毛病处理程序入口,line代表代码行标签或行号,本例为ErrHander。

第12至第16行代码是ErrHander标签。第14行代码使用Err对象的Number属性返回毛病的编号,第15行代码使用Err对象的Description返回毛病的描写内容(这描写大部份时候不讲人话,以下图所示,就凑适用吧)。

第9至第11行代码是errExit标签,作用是释放指定对象的内存。

使用Err.Number属性可以判断程序是不是存在毛病。

以下代码删除名称为”数据”的工作表。如果不存在相干工作表,则告知用户。

Sub t5()
On Error Resume Next
Application.DisplayAlerts = False
Worksheets("数据").Delete
If Err.Number = 0 Then
MsgBox "名称为数据的工作表已删除"
Else
MsgBox "不存在名称为数据的工作表"
End If
Application.DisplayAlerts = True

End Sub

第5行代码判断当前程序是不是存在毛病,当程序不存在毛病时,Err的Number属性为0。当程序存在毛病时,Number属性多是正数也多是负数,有学员将判断条件写成Err.Number > 0是毛病的。

最后,使用Err.Clear可以清除Err对象的所有属性,即清除毛病。

假定需要删除工作表名称为”工作表1″, “工作表2”, “工作表3″,并将删除的和不存在的分别弹窗告知用户,可以参考下代码遍历删除。

Sub t6()
Dim aData, strName
Dim strDelName As String, strErrName As String
On Error Resume Next
Application.DisplayAlerts = False
aData = Array("工作表1", "工作表2", "工作表3")
For Each strName In aData
Err.Clear
Worksheets(strName).Delete
If Err.Number = 0 Then
strDelName = strDelName & "," & strName
Else
strErrName = strErrName & "," & strName
End If
Next
MsgBox "以下工作表已删除:" & vbCrLf & Mid(strDelName, 2) & vbCrLf & _
"以下工作表不存在:" & vbCrLf & Mid(strErrName, 2)
Application.DisplayAlerts = True

End Sub

第4行代码忽视程序运行中的毛病。

第8行代码在每次删除工作表前都清除Err对象的所有属性。第10行代码判断Err对象的编号是不是为0,如果为0,说明工作表成功删除,否则,就假定工作簿中不存在相干工作表(摊手,是的,事实上,也有多是工作簿结构被保护了)。

代码运行后返回结果以下:

 

6、小结

同志们呐,代码调试是一个需要保持耐心和仔细的进程,这里重复一句话(小学老师说过这叫首尾呼应),一段优秀的代码3分在编写7分在调试,写一段代码你可能只需要10分钟,而调试却需要1小时——这都是很正常的。最后,用大老板的一句话勉励大家:

“惟有不忘初心、牢记使命,戒骄戒躁、砥砺前行,方能行稳致远。”

来源:HTTPs://mp.weixin.qq.com/s/YY0_eHG1ppS17AKrlnC7wA


选择英雄云云表单=选择更智能的Excel

在现代企业管理中,数据的高效管理和处理至关重要。随着信息技术的不断发展,英雄云云表单已经成为了提高数据录入、管理和分析效率的不可或缺的工具。让我们来深入探讨英雄云-云表单的几大优势。

基础字段:多样性满足业务需求

英雄云云表单中包括了各种基础字段,如单行文本多行文本数字输入框单选框复选框下拉框下拉复选框日期时间分割线等。这些字段的多样性使用户可以根据具体的业务需求,轻松进行文本、数据和时间信息的录入或修改。例如,您可以使用单行文本字段录入员工姓名、产品型号等,或者使用下拉框进行多选,根据不同情况选择更加方便的字段类型。

高级字段:提升工作效率

英雄云云表单还提供了高级字段,如地址图片附件手写签名手机子表关联数据关联查询以及流水号。这些高级字段在基础字段的基础上升级,可帮助用户完成一些琐碎的工作。例如,使用地址字段可以避免逐字打字,而流水号字段可以自动生成规律性的编号,非常适用于合同编号生成等场景。

部门成员字段:精确管理与通讯录的关联

英雄云的部门成员字段允许企业对各个部门的成员进行精确管理。用户可以通过部门成员字段获取通讯录中的部门成员信息,应用于记录报销人、报销部门等场景。这些成员字段还细分为成员单选成员多选,可根据具体需求在通讯录中选择一个或多个成员。

聚合表:数据处理更智能

英雄云聚合表功能用于对已存在的表单数据进行聚合计算,从而得到一张聚合表,后续其他表单可调用聚合表进行数据联动、关联查询和关联数据等操作完成数据处理。这一功能可应用于多种场景,如进销存管理、财务管理和门店零售管理等,帮助企业完成数据处理,提高工作效率。

表单权限设置:灵活管理数据访问

英雄云的表单权限设置允许用户根据企业的具体需求管理表单的访问和操作权限。用户可以根据系统权限或自定义权限对不同成员或团队进行权限设置,以确保数据的安全和合规性。这一功能使企业能够根据变化的业务需求和团队结构,实时调整权限设置。

自定义打印模板:文档输出更便捷

英雄云云表单支持自定义打印模板,可将表单数据转换为可打印的Word文档。用户可以根据自己的需求进行排版和编辑,将产品规格说明书等文档轻松生成。这一功能提供了一种标准化的文档输出方式,简化了信息整理的过程。

综合来看,选择英雄云云表单意味着选择更智能、更灵活、更高效的数据管理工具。无论是提高工作效率,精确管理数据,还是实现数据处理,英雄云云表单都能满足您的多样化需求,助力您的业务发展。

如果您正在寻找一款强大的云表单工具,不妨考虑英雄云,它将为您带来更多的便捷和智能,助您事半功倍。


免责声明:

本网址(www.yingxiongyun.com)发布的材料主要源于独立创作和网友匿名投稿。此处提供的所有信息仅供参考之用。我们致力于提供准确且可信的信息,但不对材料的完整性或真实性作出任何保证。用户应自行验证相关信息的正确性,并对其决策承担全部责任。对于由于信息的错误、不准确或遗漏所造成的任何损失,本网址不承担任何法律责任。本网站所展示的所有内容,如文字、图像、标志、音频、视频、软件和程序等的版权均属于原创作者。如果任何组织或个人认为网站内容可能侵犯其知识产权,或包含不准确之处,请即刻联系我们进行相应处理。

上一篇:更多有关条件格式的内容……-英雄云拓展知识分享
下一篇:数据查询的最好搭档——数据查询的最好搭档——INDEX函数和MATCH函数函数和MATCH函数-英雄云拓展知识分享
相关文章

 发表评论

暂时没有评论,来抢沙发吧~

×