【Excel VBA编程】代码功能扩展实战:三步让旧代码换新颜
总是听到或看到有人问,编程好学吗?如何入门?多久能学会?它能做些什么?怎么写代码呀?…如果你也有类似的问题那就赶快关注我的公众号,本公众号一直在不间断地分享编程案例和实用技巧,无论您想提升自动化办公效率还是编程技能,都能收获满满
在别人手里,感觉代码就像个听话的乖宝宝,大段的代码复制粘贴,修修剪剪三两下就能正常运行。可一到自己手里,代码却变成了“叛逆少年”,稍微动一下就报错,让人头疼不已
其实每位编程新手都会遇到这类问题,那要如何改变这种状态呢?建议大家按照以下三个步骤执行:
-
首先,在动手修改代码之前,必须深入理解原有代码的逻辑与整体结构,这是所有后续工作的基石
-
必要时,对现有代码进行调整,使其结构更清晰、更易于扩展,然后立即运行测试,确保调整后的代码没有破坏原有功能
-
最后,以“小步快跑”的方式,每次只添加一小块新功能,并立即进行测试验证
接下来,我们将通过一个具体案例,详细演示如何按照上述步骤进行实际操作
基础功能需求
如下图所示,我们通过表一数据,按照月份和产品两个维度统计出了表二数据(具体实现代码查看:CountByMonthAndProd)

聚焦到表二中数据,如果能在表格最后一行汇总各产品的总计数据,或在最后一列汇总各月份的总计数据,这张表格的呈现效果会更加完整和清晰预期效果:

转换到编程问题:在原有代码功能的基础上,增加总计功能
扩充功能实现
分析原有代码CountByMonthAndProd逻辑和整体结构,千万不要被长代码吓到。原有代码整体结构:读取数据 -> 使用字典进行高效的分组和汇总 -> 将结果格式化输出,很清晰没有必要调整代码了
Sub CountByMonthAndProd()' 声明变量Dim ws As WorksheetDim lastRow As Long, i As LongDim dict As Object, monthList As Object, productList As ObjectDim arrData As Variant, arrOutput() As VariantDim monthKey As String, productKey As StringDim monthIndex As Long, productIndex As LongDim totalSales As Double' 关闭屏幕更新Application.ScreenUpdating = False' 设置数据所在的工作表(当前活动工作表)Set ws = ActiveSheet' 获取数据最后一行lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).RowIf lastRow < 2 Then Exit Sub ' 如果没有数据则退出' 将原始数据读入数组,提高处理速度arrData = ws.Range("A2:C" & lastRow).Value' 创建字典对象Set dict = CreateObject("Scripting.Dictionary")Set monthList = CreateObject("Scripting.Dictionary")Set productList = CreateObject("Scripting.Dictionary")' 遍历数据,进行分组汇总For i = 1 To UBound(arrData, 1)monthKey = Trim(arrData(i, 1)) ' A列:月份productKey = Trim(arrData(i, 2)) ' B列:产品totalSales = Val(arrData(i, 3)) ' C列:销量' 记录出现的唯一月份和产品,用于构建输出表头If Not monthList.exists(monthKey) ThenmonthList.Add monthKey, monthList.Count + 1End IfIf Not productList.exists(productKey) ThenproductList.Add productKey, productList.Count + 1End If' 构建复合键,用于在字典中唯一标识一个“月份-产品”组合Dim compositeKey As StringcompositeKey = monthKey & "|" & productKey' 如果该组合已存在,则累加销量;否则,创建新条目If dict.exists(compositeKey) Thendict(compositeKey) = dict(compositeKey) + totalSalesElsedict.Add compositeKey, totalSalesEnd IfNext i' --- 输出结果 ---' 清空输出区域(从E列开始)ws.Range("E1").CurrentRegion.ClearContents' 将月份输出到E列(从第2行开始)Dim monthKeys As VariantmonthKeys = monthList.keysFor i = 0 To monthList.Count - 1ws.Cells(i + 2, "E").Value = monthKeys(i) ' E列输出月份Next iws.Cells(1, "E").Value = "月份" ' E1标题' 将产品输出到一行(从F1开始)Dim productKeys As VariantproductKeys = productList.keysFor i = 0 To productList.Count - 1ws.Cells(1, i + 6).Value = productKeys(i) ' 从F1开始输出产品名Next i' 填充交叉统计的总销量Dim outRow As Long, outCol As LongDim eKeys As VariantFor Each eKeys In dict.keys' 拆分复合键,获取月份和产品Dim keyParts() As StringkeyParts = Split(eKeys, "|")monthKey = keyParts(0)productKey = keyParts(1)' 查找该月份和产品在输出表中的位置outRow = monthList(monthKey) + 1 ' +1 因为第1行是标题outCol = productList(productKey) + 5 ' +5 因为从F列(第6列)开始' 将总销量填入对应单元格ws.Cells(outRow, outCol).Value = dict(eKeys)Next eKeys' 恢复屏幕更新Application.ScreenUpdating = TrueMsgBox "统计完成!", vbInformationEnd Sub
既然不需要调整代码,直接进入到第三步,“小步快跑”方式,我们先增加最后一行按产品维度的总计数据

为了将影响降低到最小并且代码量也最小,可以考虑使用现成的数据及工作表函数实现。新增代码添加位置,第92行代码之后
待增加代码1:利用字典对象获取数据区域,即最后一行和最后一列
Dim lastDataRow As LonglastDataRow = monthList.Count + 1 ' 数据最后一行(标题行+数据行数)Dim lastDataCol As LonglastDataCol = productList.Count + 5 ' 数据最后一列(E列是第5列,加上产品列数)
待增加代码2:使用Application.WorksheetFunction.Sum求和后输出即可
ws.Cells(lastDataRow + 1, "E").Value = "总计"' 计算每个产品的列总计For i = 6 To lastDataCol '从F列开始Dim colTotal As Double' 使用WorksheetFunction.Sum求和colTotal = Application.WorksheetFunction.Sum(ws.Range(ws.Cells(2, i), ws.Cells(lastDataRow, i)))' 将列总计填入最后一行ws.Cells(lastDataRow + 1, i).Value = colTotalNext i
好了,大家按照这个方法及思路,尝试增加月总计列的数据吧

夜雨聆风
