
本文于2023年9月25日首发于本人同名其他平台,更多文章案例请搜索关注!
内容提要
打印模板更改
大家好,我是冷水泡茶,9月11日我们分享过一个案例【销货小票批量打印/电商小工具】,今天上论坛发现,楼主又有了新的需求:

新的打印格式与打印方式变化:

要求就在小票打印模板这张表中打印,不要“Print”这张表。
感觉不难,但是有点烦,没办法,好人做到底吧,按他的要求进行了调整。
一、打印模板初始化
在原来的模板中打印,主要难度在于,每次打印要判断商品名称的行数,多余的行要删除。当然,也算不上难。我们定位“商品名称”与商品总价”的行号(line1、line2),如果相差超过2,就表示有多余的行,把它删除,只留一条商品名称空白行,恢复成原来模板的格式:
With ws .Activate Set cell = ws.Columns("B").Find(What:="商品名称", LookIn:=xlValues, LookAt:=xlPart) line1 = cell.Row Set cell = ws.Columns("B").Find(What:="商品总价", LookIn:=xlValues, LookAt:=xlPart) line2 = cell.Row If line2 - line1 > 2 Then ws.Rows(line1 + 2 & ":" & line2 - 1).Delete End If line2 = line1 + 2 .Rows(line1 + 1).ClearContentsEnd With
这里ws就是“小票模板”表。这里line1就代码“商品名称”行,line2代表“商品总价”行,在删除多余行之后,把line2的值更新。
恢复模板还有另一种方式,就是把模板的各个字段重新写入工作表,字段也不算很多,可以直接一个字段一个字段地写入工作表,也可以创建一个跟打印区域一样大小的数组,一次性写入。
不过,这种方式可能要设置单元格的格式,还是有点繁琐的。
二、各个字段的取值
在插入行之前,我们先把除商品名称外的字段进行取值。
原来是在同一列,我们直接循环行号,对应取值。现在变为2列了,是不是还要再循环一次?表头又多了一个“社区“字段,我猜应该是“打印数据”表中的“地区”字段吧,但奇怪的是它的值放到了字段的左边(其他字段的值都在字段的右边)。后来干脆循环整个数据区域吧,定位字段并赋值。
lastRow = ws.UsedRange.Rows.CountSet rng = ws.Range("B2:E" & lastRow)For Each cell In rng If InStr(cell.Value, "电话") Then cell.Offset(0, 1).NumberFormatLocal = "@" End If If InStr(cell.Value, "社区") Then cell.Offset(0, -1).Value = .ListItems(i).SubItems(Pxy(tbTitle, "下单地区") - 1) ElseIf InStr(cell.Value, "下单时间") Then cell.Offset(0, 1).Value = .ListItems(i).Text ElseIf InStr(cell.Value, "商品总价") Then cell.Offset(0, 3).Value = .ListItems(i).SubItems(Pxy(tbTitle, "商品总价") - 1) ElseIf cell <> "" Then itemname = Replace(cell.Value, ":", "") ipos = Pxy(tbTitle, itemname) If ipos > 0 Then cell.Offset(0, 1).Value = .ListItems(i).SubItems(ipos - 1) End If End IfNext
这里主要采用Range的Offset方法,不管你是上下左右,都可以获得要赋值的单元格位置。我们采用自定义函数Pxy来取得字段值在ListView中的位置,这样,基本可以忽略字段的顺序问题,除了第一个字段“下单时间”,在ListView中是Text,它的位置不能改变。
三、商品名称等字段的取值
我们还是采用Pxy函数定位字段。商品名称这里比较特殊,第一个与最后一个商品名称不能变。
For j = pos1 To pos2 If Len(.ListItems(i).SubItems(j - 1)) > 0 Then ws.Cells(line1 + 1 + k, 2) = tbTitle(j - 1) ws.Cells(line1 + 1 + k, 3) = arrPrice(j - pos1) Set cell = ws.Cells(line1 + 1 + k, 4) cell.Value = .ListItems(i).SubItems(j - 1) cell.Offset(0, 1) = cell.Value * cell.Offset(0, -1).Value k = k + 1 End IfNext
这里pos1、pos2就是首尾商品名称的位置,如果它们及其间的Listview的值不为空,也就是数量不为0,那么我们就把商品名称、单价、数量写入工作表。“金额”通过单价*数量计算得出。这里也采用了Range的Offset方法。
四、打印区域的设置
由于打印模板的标题是“小票打印模板”,这行应该是不能打印出来的,加上我看他的打印预览中也没有这个标题,所以,这里不是全部打印,是“B2:E”&lastRow这样一上区域,它是随着商品数变化的。
Set cell = ws.Columns("B").Find(What:="确认签收", LookIn:=xlValues, LookAt:=xlPart)lastRow = cell.RowSet ps = ws.PageSetupps.PrintArea = ws.Range("B2:E" & lastRow).Addressws.PrintOut Copies:=1
这里根据最后一行字段值“确认签收”来定位最后一行,设置打印区域。
五、代码优化调整
1、ws.PrintOut代码原来有两处,把它移到IF语句外面,只需要一处就可以了。原来其所在的IF语句,是用来根据不同情况,给工作表单元格赋值,IF语句赋值完成后打印。
2、原来在插入行、写入数据的时候,采用了固定的行作为参照:

调整为根据计算出来的“商品名称”、“商品总价”的行作为基础,具有相对的灵活性:

六、总结
1、实现功能需求的方法多种多样,我们可以多多偿试。
2、虽然我们能通过代码实现这样那样的功能,但我们在设计表格、模板的时候,必须要谨慎考虑,一旦敲定,就不要轻易去改变。否则可能会造成很大的麻烦。
3、另外,我们在设置模板的时候,应该做到表格之间相同字段的名称统一,就象这位他的“打印数据”表头字段与“小票模板”中的字段有好几个是不对应的,这不是好的做法。
好,今天就到这吧。更新后的完整代码我放到第二条文章,感兴趣朋友可以去看一看。
~~~~~~End~~~~~~
喜欢就点个赞、点在看、留言评论、分享一下呗!感谢支持!