【用实战学VBA】拒绝重复操作,VBA按固定格式批量输出,并没有那么难

【用实战学VBA】拒绝重复操作,VBA按固定格式批量输出,并没有那么难

大家好~我是一分钟学Excel,VBA的基础系列目前到了第三期,前两期都比较简单,今天呢,我们来一些实际工作或生活中会涉及到的案例。

老样子,学习时间~



今天的练习册有两个工作表,一个表格是送货单,另一个是数据原始表格(销项发票)。

(送货单)


(销项发票)




聪明的你一定知道了,我们需要做的便是将销项发票中的数据填入到送货单对应的单元格之中。就像这样:



当然,一张是不够的,原始表格(销项发票)中有51行数据,也就意味着,在不进行数据汇总的情况下,我们要批量输出51张。

其实生活中有许多类似这样的工作,比如工资单、发票录入等等。都同属于重复且繁琐的操作。而使用VBA的好处是,可以通过代码来一键实现批量处理的操作。


基础操作


在开始代码之前,我们先设想一下,如果不使用VBA,我们的操作会是什么样的。最基础的操作便是复制粘贴,从原始表格中复制数据,然后再粘贴到对应的单元格中。总结下来,便是这几步。

  1. 选中销项发票工作表;
  2. 复制指定单元格数据;
  3. 选中送货单所在工作表;
  4. 粘贴指定单元格数据。


而这几步,如果使用代码编写是这样的。



我们在上一期中学会了如何去使用变量来存储数据与给数据赋值。便不用再对数据进行复制与粘贴。还记得是怎么操作的吗?我们来试着编写一下。

首先,先声明一个变量,为文本类型。然后开始第一步,选中原始表格数据表,将E5单元格的数据赋值给变量客户,最后回到送货单的工作表中,将客户的值赋值给B5单元格。这样一来,便完成来基础的步骤。而其余的数据可以依照这样的方式进行同样的赋值操作。

  • 代码
Sub test()
Dim 客户 As String
Sheets("销项发票").Select
客户 = Range("E5").Value
Sheets("Sheet1").Select
Range("B5").Value = 客户
End Sub
  • 运行效果



从运行效果中,处于原始数据表格(销项发票)中的客户名称被指定的填入到了送货单的收获单位旁的单元格中。在我说下一步之前,我希望你可以先自己练练手,将这一步完成。熟悉vba语句的编写。

剩下的便是以这样变量赋值的方式,将每一个数据依次填充到送货单中。

  • 代码
Sub test()
Dim 客户 As String
Sheets("销项发票").Select
客户 = Range("E5").Value
日期 = Range("D5").Value
货物 = Range("G5").Value
规格 = Range("H5").Value
单位 = Range("I5").Value
数量 = Range("J5").Value
单价 = Range("K5").Value
金额 = Range("L5").Value
Sheets("Sheet1").Select
Range("B5").Value = 客户
Range("F5").Value = 日期
Range("A9").Value = 货物
Range("B9").Value = 规格
Range("C9").Value = 单位
Range("D9").Value = 数量
Range("E9").Value = 单价
Range("F9").Value = 金额
End Sub


  • 运行效果



别直接复制粘贴哦~ 一定要自己写一遍,这样才能记住基础语句的用法。第一张单子填充完毕后,接下来,便是复制送货单,到下面的空白区域去进行粘贴。

  • 代码
Range("A1:G16").Select
Selection.Copy
Range("A18").Select
ActiveSheet.Paste


  • 运行效果



如果我们需要粘贴51张送货单的话,就需要粘贴51次,也就是51*2,102行代码。未免也太多了。这样一来,还不如手动复制粘贴来的快。像这样重复的工作,可以用VBA中的【循环】来实现。


循环



循环,这个词语也出现在许多编程语言之中。区分人类与动物的标志之一在于:人类懂得制造和使用生产工具从事生产劳动。

在生活中,你可能需要去制作很多相似的合同,本来需要一个一个手动输入,而计算机通过【循环】,就可以依照某些规则帮你填写。你就可以正大光明的“上班偷懒”了。在VBA中,与其他编程语言一样,有for循环与while循环。在今天的案例中,我们主要通过for循环去解决重复性问题。

【for循环】可以规定循环次数,语法是关键字for,意味着for的循环展开,后跟上循环的次数,便是x等于多少到多少。



如果【x = 1 to 3】的话,则循环3次。
第一次:x = 1;第二次:x = 2,第三次:x = 3。
循环到3的时候,配上【Next语句】,循环结束。



下面,我们在代码中编写for循环语句,来看看它的具体应用。首先,定义客户的变量用于存储表格中E5单元格的值。然后使用MsgBox打印变量的内容。



这里可以看到,MsgBox的弹窗出现了一次,这时候,我们加上循环,使其循环三次。



这里暂停一下,可以看到这里我全选了下面的语句,然后按下了键盘上的【Tab键】,让这些语句的前方都出现了 四个空格 或者一个 tab键 的距离。为什么要这样做呢?


缩进


我们在日常处理Word文本时,常常说:首行缩进2个字符。在写文章时,我们设置好首行缩进能够帮助我们更好的分清内容层次和段落,便于理解。



对于VBA而言,缩进这类固定格式,也会帮助VBA区分代码之间的层次,理解条件执行的逻辑和先后顺序。比如For语句与Next语句是属于平行关系,而缩进后的语句与For语句则属于层级关系。




不过需要你注意的是:写文章时,【首行缩进】一般是【两个字符】;而在写代码时,【缩进】代表的是【四个空格】或【一个Tab键】。



好,回到案例。循环语句写完后我们来看看运行效果。可以看到加了循环之后,msgbox出现了三次循环。修改循环次数为5,运行结果便出现了5次。这便是循环的基础使用。



接下来,我们将循环加入表格之中,用于复制整个送货单。从表格中可以看出,一共有51条数据,也就是说,我们需要51个送货单。想要循环复制粘贴51个送货单,很简单,只需要写出【For x = 1 to 51】就可以了。

但是这样会有一个问题,我们先来看看问题所在。为了方便测试,我先设置3次循环。这里可以看出,程序一直在同一个位置粘贴,与我们想要的效果不同。




我们想要的效果是,粘贴了一个送货单后,隔一行再粘贴一个。导致结果与预期不同的原因是,我们在程序中指定了在单元格A8处粘贴,所以导致一直重复在同一个位置粘贴。那么,如何能让程序智能的知道隔一行粘贴呢?

观察一下表格,可以发现第一个送货单一共占了16行,隔一行粘贴的话,便是在第18行开始粘贴。也就是说,我们的循环粘贴每一次都要留出17行的空间才能不发生错位的情况。



明白了一个送货单需要17行的空间后,我们需要做的便是让程序知道,完成一次粘贴后,隔17行再进行粘贴。这时候,我们就可以使用变量。

变量中的数据可以是一直变化的,这里,我们创建一个变量a。设置变量的初始值为 a = 1 ,变量的值可以根据循环的每一次次数发生改变。每一次循环,我们让变量 a + 17。


这样一来,第一次循环,a的值是18,第二次循环,变量a的值是33。以此类推。然后我们将变量a的值,用连接符号【&】与单元格连接起来。这样开始循环的话,第一次循环, 单元格A18区域被选中,第二次循环,单元格A33区域被选中 ,以此类推来解决之前出现的重复位置粘贴的问题。



设想完毕后,我们编写代码来测试效果。
首先我们声明变量a为数字类型,然后设置变量a的初始值为0,在循环中让变量a随着循环的次数实现变量a的增值,每一次增加17。最后,将变量a与单元格区域用连接符号进行连接【&】。编写完毕后,把循环次数加大到51次,看看运行效果,测试程序效果。

  • 代码
Dim a As Integer
For x = 1 To 51
    a = a + 17
    Sheets("Sheet1").Select
    Range("A1:G16").Select
    Selection.Copy
    Range("A" & a).Select
    ActiveSheet.Paste
Next


  • 运行效果



从运行效果可以看出。目前程序已经完成了我们想要的送货单的粘贴效果。那么,现在只剩下了一个问题,那便是, 如何让程序判断原始数据表格,自动填充数据?

带着这个问题,我们来观察一下原始数据表格。在表格中,我们想要的是,程序可以自动从第一行往下读取每一行的数据,从而填充到每一张送货单之中。
仔细观察表格,以 客户名称 为例,程序将会从 E5单元格出发,依次向下,从E5到E6。再从E6到E7 。这时候你会发现一个规律,那便是 列不变,行在变 。且每一次行的变化是在原先的单位上+1。



发现规律之后,解决问题就简单了许多。同样的,我们可以用变量来解决这个问题。设置一个【变量b】。
这里,我们也可以将它放置于循环之中,每一次循环,变量便根据循环的次数进行递增。代入到单元格中,便是, 第一次循环,单元格B5被选中,第二次循环单元格B6被选中 。以此类推。



根据这种设想,我们来编写代码。先声明变量B为整数类型。然后,将b放入循环之中,每一次的循环,b的值都会根据循环递增。以客户名称为例,代入变量b。根据这种设想,我们来编写代码。

先声明变量客户为文本类型,变量b为整数类型。然后,将b放入循环之中,每一次的循环,b的值都会根据循环递增。以客户名称为例,代入变量b。再将客户的值赋值给送货单对应的区域即可。运行程序,看看效果。

  • 代码
Sub test()
Dim 客户 As String, 日期 As Date, 货物 As String, 规格 As String, 单位 As String
Dim 数量 As Integer, 单价 As Single, 金额 As Single
Dim a As Integer
a = -16
For x = 1 To 55
    a = a + 17
    b = 4 + x
    Sheets("销项发票").Select
    客户 = Range("E" & b).Value
    日期 = Range("D" & b).Value
    货物 = Range("G" & b).Value
    规格 = Range("H" & b).Value
    单位 = Range("I" & b).Value
    数量 = Range("J" & b).Value
    单价 = Range("K" & b).Value
    金额 = Range("L" & b).Value
    Sheets("Sheet1").Select
    Range("B5").Value = 客户
    Range("F5").Value = 日期
    Range("A9").Value = 货物
    Range("B9").Value = 规格
    Range("C9").Value = 单位
    Range("D9").Value = 数量
    Range("E9").Value = 单价
    Range("F9").Value = 金额
    Range("A1:G16").Select