【2.使用VBA自动填充Excel工作表】
目录
- 前言
- 什么是VBA
- 如何使用Excel中的VBA
- 简单基础入门
- 控制台输出信息
- 定义过程(功能)
- 定义变量
- 常用的数据类型
- Set
- 循环
- For To
- 我的需求
- 开发过程
- 效果演示
- 文件情况
- 测试填充源文件
- 测试填充目标文件
- 全部完整的代码
- sheet1中的代码,对应A公司工作表
- UserForm1的代码
- 待续
- 基础逻辑完善
- 获取行号
- 遍历日期算法逻辑
- 提升对单元格等对象的操作知识
- 功能升级
前言
上一篇文章我使用了Excel中的Index和Match函数实现可以根据之前打过的数据去自动填充内容。在对账的时候可以帮助我们节省很多时间。但是,这样不够直接、更不够快
。
做过对账单和送货单的人都知道,送货单在出货的时候要打,可能一天一个公司打个一两次。要是我在打送货单的时候,对账单也能自动根据送货单的内容自动填充就好啦
。
如此细致的功能,我目前只想到了使用Python和VBA。
如果要实现日常的使用,VBA应该就够用了。
什么是VBA
VBA是Visual Basic for Applications
的缩写,它是一种事件驱动
的编程语言,由微软公司开发。VBA主要用于Microsoft Office套件中的应用程序,如Excel、Word、Access、PowerPoint等,允许用户通过编写宏和自定义函数来自动化任务和扩展应用程序的功能
。
VBA基于Visual Basic编程语言,它提供了一套丰富的编程工具和对象模型,使得开发者可以创建复杂的自动化脚本和自定义用户界面
。使用VBA,用户可以:
自动化重复性任务:通过编写宏来减少手动操作,提高工作效率。
数据处理和分析:在Excel中进行复杂的数据操作和分析。
用户界面定制
:在Word或Excel中创建自定义的对话框和表单
。
与其他应用程序交互:通过VBA编写的代码可以与其他应用程序或数据库进行交互
。
发明背景
VBA的发明时间可以追溯到1994年左右,当时随着Office 95的发布,VBA作为其宏语言的一部分被引入。它与传统的宏语言不同,提供了面向对象的程序设计方法,并拥有相当完整的程序设计语言。VBA易于学习掌握,可以使用宏记录器记录用户的各种操作并将其转换为VBA程序代码,从而实现工作自动化
。
VBA与Visual Basic(VB)具有相似的语言结构,从语言结构上讲,VBA是VB的一个子集,它们的语法结构是一样的。VB是一种独立的开发工具,而VBA则必须依附于Office应用程序
。VBA专门用于Office的各应用程序中,如Word、Excel、Access等,它与主应用程序之间的通信变得简单而高效。
VBA的编程能力介于低级语言和高级语言之间,它继承了Visual Basic的部分特性和语法,因此具有更强的编程能力和灵活性。然而,VBA的运行速度相对较慢,因为它是通过解释执行而非编译执行的
。此外,VBA主要用于Office软件的宏编程和自动化处理,对于其他领域的开发可能不太适用。
如何使用Excel中的VBA
参考链接小步教程
首先,要想使用VBA,需要新建启用宏的工作簿
,文件后缀名是xlsm
然后再文件-选项中-自定义功能区 选中开发工具
简单基础入门
控制台输出信息
使用
Debug.Print ""
以及立即窗口(控制台)
定义过程(功能)
Sub 函数名End Sub
定义变量
Dim 变量名 As 数据类型
Dim a As String
常用的数据类型
- Workbook 工作簿 表示整个Excel文件,包括所有的工作表
- Worksheet 工作表 表示单个工作表
- String 字符串
- Long 存储大整数,比如行号 (-2,147,483,648 到 2,147,483,647)
Set
给自己定义的变量指向一个对象
' 设置源工作表Set wsSource = ThisWorkbook.Sheets(sourceSheetName)' 打开目标工作簿Set wbTarget = Workbooks.Open("C:\Users\Administrator\Desktop\nosee\EXCEL\测试填充目标文件.xlsm")
循环
VBA循环结构包括四类结构:For To、For Each、While、Do While。
For To
退出当前循环
退出整个循环
我的需求
要有图形化界面
- 可以自己选择需要对账的工作表和送货表
- 自己可以选择要对账的日期和范围 (可能要用到正则表达式)
- 使用用户界面交互 选择送货单的位置和工作表 对账单的位置和表
开发过程
效果演示
视频如下:
文件情况
测试填充源文件
(这是代码里的名称,在实际工作中就对应送货单)
如上图,比较值得注意的点是:
- 序号那种字段名称居然占了两行,这就导致有效数据是日期行加3,不知道做这个送货单的人怎么想的🙄,当时没注意看坑死我了。
- 还有就是第九行的内容看起来横跨了很多单元格,但是其实只是在A列而已,只是没有展开
- 还有一个细节就是,对比一下可以看出,在DATE 2024/8/31的下面三行就是有用的数据,而且有用的数据那一行的C、D列都有数据,这些都是我后面用来判断数据有效性的依据
测试填充目标文件
(这个也是代码里的名称,实际中对应的是对账单)
这个没什么好说的,以后希望也能把日期附在内容前以方便分开
全部完整的代码
sheet1中的代码,对应A公司工作表
'全局变量 用来接收文件信息Public targetSheetName As StringPublic sourceSheetName As StringPublic targetFilePath As StringPublic dateToCheck As StringSub UserForm_Initialize()UserForm1.Show '打开用户界面
End SubSub CopyDataBasedOnDate() '定义函数 用户界面Dim wsSource As Worksheet '定义变量 Worksheet 是Excel中工作表的对象类型,表示单个工作表。源工作簿不用设置Dim wbTarget As Workbook 'Workbook 是Excel中工作簿的对象类型,表示整个Excel文件,包括所有的工作表。Dim lastRow As LongDim targetRowA As LongDim targetRowC As LongDim targetRow As Long 'Long 是VBA中的一种数据类型,用于存储较大的整数(-2,147,483,648 到 2,147,483,647)' 设置源工作表Set wsSource = ThisWorkbook.Sheets(sourceSheetName)' 打开目标工作簿Set wbTarget = Workbooks.Open(targetFilePath)' 找到目标工作表Dim wssTarget As Worksheet' ############设置异常?On Error Resume Next '这行代码是一个错误处理语句,它告诉VBA在遇到错误时不要显示错误消息,而是继续执行下一行代码。这是错误处理的开始。Set wssTarget = wbTarget.Sheets(targetSheetName) '通过 wsTarget 工作簿对象来访问名为 targetSheetName 的工作表,If wssTarget Is Nothing Then ' Nothing 表示一个变量没有引用任何对象。MsgBox "目标工作表不存在"Exit Sub '这行代码会立即退出当前正在执行的子程序(Sub)。如果没有找到工作表,程序将不会继续执行后面的代码。End IfOn Error GoTo 0 '这行代码用于关闭之前启用的错误处理。在遇到错误时停止执行并显示错误消息。这行代码通常放在错误处理代码的最后,以确保错误处理的范围仅限于特定的代码块。' ############获取源工作表的最后一行 这里可能要调lastRow = wsSource.Cells(wsSource.Rows.Count, "A").End(xlUp).RowtargetRowA = wssTarget.Cells(wssTarget.Rows.Count, "A").End(xlUp).RowtargetRowC = wssTarget.Cells(wssTarget.Rows.Count, "C").End(xlUp).RowtargetRow = Application.Max(targetRowA, targetRowC) + 2 '因为最后一行也是两行合并' ##############遍历源工作表中的所有行 应该要换个判断条件或者方式 根据日期,直到下一个日期Dim i As LongFor i = 1 To lastRow '遍历循环If wsSource.Cells(i, "A").Value = dateToCheck Then '如果第i行是要对账的日期For j = i + 3 To lastRow '日期内循环If j - i > 13 Then '3是必要的内容 因为有客套话 假如内容十行的话 就够了'最好的办法还是判断日期内循环有没有到下一个日期 到了就直接跳 结束了i = j - 1Exit ForEnd IfIf wsSource.Cells(j, "A").Value = dateToCheck Then '如果已经碰到下一个日期 比如同一天的 还有可能不是同一天的i = j - 1 '节省遍历循环的时间 跳出循环Exit ForEnd IfIf Not IsEmpty(wsSource.Cells(j, "C").Value) And Not IsEmpty(wsSource.Cells(j, "D").Value) Then'如果没有到下一个日期并且数据有效 c列d列不都为空就可以了wsSource.Rows(j).Copy Destination:=wssTarget.Rows(targetRow) 'targetRow = targetRow + 1End IfNext jEnd IfNext i' ############保存并关闭目标工作簿wbTarget.Save
' wbTarget.CloseMsgBox "数据复制完成"
End Sub
UserForm1的代码
Sub dateToCheckCommandButton_Click()Sheet1.dateToCheck = dateToCheckTextBox.Text
End SubSub sourceSheetNameCommandButton_Click()Sheet1.sourceSheetName = sourceSheetNameTextBox.Text ' 把文本框的内容赋值给源工作表名字变量
End Sub
Sub targetFilePathCommandButton_Click()Sheet1.targetFilePath = targetFilePathTextBox.Text
End SubSub targetSheetNameCommandButton_Click()Sheet1.targetSheetName = targetSheetNameTextBox.Text ' 把文本框的内容赋值给目标工作表名字变量
End SubSub CommitCommandButton_Click()Sheet1.CopyDataBasedOnDate '调用复制程序
End Sub
待续
基础逻辑完善
获取行号
获取源文件行号是从下往上找获取A、C两个必定会有内容的列的单元格不为空的逻辑,但是别人的工作表不一定是这样的
- 现在使用的是cell和max函数
lastRow = wsSource.Cells(wsSource.Rows.Count, "A").End(xlUp).Row
targetRowA = wssTarget.Cells(wssTarget.Rows.Count, "A").End(xlUp).Row
targetRowC = wssTarget.Cells(wssTarget.Rows.Count, "C").End(xlUp).Row
targetRow = Application.Max(targetRowA, targetRowC) + 2 '因为最后一行也是两行合并
搜了一下还可以用下面这些方法,日后试试
- 使用UsedRange属性:
UsedRange属性可以返回工作表中使用过的范围,然后可以通过这个范围来找到最后一行。
Dim lastRow As Long
lastRow = ThisWorkbook.Worksheets("Sheet1").UsedRange.Rows.Count
- 使用SpecialCells方法:
这个方法可以用来找到最后一行,特别是当表格中有空行时。
Dim lastRow As Long
On Error Resume Next ' 如果没有找到单元格,避免错误
lastRow = ThisWorkbook.Worksheets("Sheet1").Cells.SpecialCells(xlCellTypeLastCell).Row
On Error GoTo 0 ' 重新启用错误报告
遍历日期算法逻辑
For i = 1 To lastRow '遍历循环If wsSource.Cells(i, "A").Value = dateToCheck Then '如果第i行是要对账的日期For j = i + 3 To lastRow '日期内循环If j - i > 13 Then '3是必要的内容 因为有客套话 假如内容十行的话 就够了'最好的办法还是判断日期内循环有没有到下一个日期 到了就直接跳 结束了i = j - 1Exit ForEnd IfIf wsSource.Cells(j, "A").Value = dateToCheck Then '如果已经碰到下一个日期 比如同一天的 还有可能不是同一天的i = j - 1 '节省遍历循环的时间 跳出循环Exit ForEnd IfIf Not IsEmpty(wsSource.Cells(j, "C").Value) And Not IsEmpty(wsSource.Cells(j, "D").Value) Then'如果没有到下一个日期并且数据有效 c列d列不都为空就可以了wsSource.Rows(j).Copy Destination:=wssTarget.Rows(targetRow) 'targetRow = targetRow + 1End IfNext jEnd IfNext i
我在源文件遍历日期的方法是从第一行查找到最后一行,如果遇到匹配的字符串,就再内嵌一个循环,因为一个日期内有很多数据需要一行行地复制过去,还要判断数据的有效性
这里解释一下
For j = i +3是因为序号那一行是两行合并,所以有效数据是日期+3行 ,j-i>13是因为一般来说一次送货不会超过十种货,也就是对应十行数据了
提升对单元格等对象的操作知识
可以看出我对对单元格本身不了解 内置函数和属性不熟 所以判断数据有效性的条件很抽象
功能升级
-
目前可以实现在页面不关闭的情况下一次插入一天的对账信息,但是这样也不够快,
要是能一次插入一个时间范围内的对账信息就好了
,估计要新增很多判断逻辑,以及对字符串的一些操作处理(因为有时候你的源工作表不一定就是2024/8/31这样的数据),最好是再做一个控件。 -
输入文件路径有点麻烦,尝试改进成浏览文件的方式选中。
-
未来要加入
判断插入的数据是否是已有数据
的逻辑才行,否则会重复插入
而且最好能提示用户“重复插入了” -
从送货单复制的数据到对账单并不是会完美一一对应,因为对账单和送货单所需要的信息不一定是一一对应的,可能会多或者少或者顺序不对,还有一些比较奇葩的是粘贴的目标列合并了,
所以要怎么匹配列去进行粘贴 是一个问题
相关文章:

【2.使用VBA自动填充Excel工作表】
目录 前言什么是VBA如何使用Excel中的VBA简单基础入门控制台输出信息定义过程(功能)定义变量常用的数据类型Set循环For To 我的需求开发过程效果演示文件情况测试填充源文件测试填充目标文件 全部完整的代码sheet1中的代码,对应A公司工作表Us…...

算法记录——链表
2.链表 2.1判断是否是回文链表 1.方法一:利用栈反转链表 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* ListNode(int val, ListNode…...
EasyExcel实现百万数据批量导出
当数据量比较大时,例如数据量达到百万级,传统的一次读取到内存中在写入excel文件的方法便不再适用了,可能会导致内存溢出;而且一次性将数据写入一张sheet工作表也不太好。 但我们可以选择数据分片的方式批量写入多个工作表。 测试…...
兆易GD32E508的SHRTIM配置 主从定时器 产生2对相位可调互补PWM 带死区
如有技术问题及技术需求请加作者微信! GD32E5系列MCU是基于Arm Cortex-M33处理器的32位通用微控制器。Cortex-M33处理器基于Armv8架构,处理器主频最高可达180MHz,支持强大的可扩展指令集,包括通用数据处理I/O控制任务、增强的数据处理位域操作、DSP和浮点运算器(FPU)。 GD…...
数据归组工具
利用C#将数据 [ {"name":"A","fzh":1}, {"name":"A","fzh":2}, {"name":"A","fzh":3}, {"name":"B","fzh":4}, {"name":"B",&…...
JavaScript 中的闭包的形成及使用场景
JavaScript 中的闭包 闭包(Closure) 是 JavaScript 中一个非常重要且独特的概念,它指的是 函数能够记住并访问其词法作用域内的变量,即使这个函数在其词法作用域之外执行。 通俗地说,闭包是 一个函数可以“记住”它在…...

后端返回内容有换行标识,前端如何识别换行
<br/>的话 用 v-html \n 可以用css样式 white-space: pre-wrap 后端返回结果 前端...
服务器被挂马,导致网站首页被更改怎么解决
当服务器被挂马并导致网站首页被篡改时,说明服务器或网站的安全性遭到破坏。为了修复并防止未来的攻击,你可以按照以下步骤进行操作: 1. 立即下线网站 目的:防止恶意软件进一步传播,保护用户数据和防止攻击者继续对网…...

Android 利用OSMdroid开发GIS
1、地址 Github地址:https://gitee.com/mirrors/osmdroid Git地址: GitCode - 全球开发者的开源社区,开源代码托管平台 Git下载包地址:Releases osmdroid/osmdroid GitHub 新建项目 osmdroid在线: (1)…...

一文上手skywalking【上】
一、skywalking预览 1.1 skywalking 概述 Apache SkyWalking, 适用于分布式系统的应用程序性能监控工具,专为微服务、云原生和基于容器的 (Kubernetes) 架构而设计。官方地址: https://skywalking.apache.org/ 适用于分布式系统的应用程…...

【JavaScript】JQuery基础知识及应用
一、JQuery的导入方法 https://editor.csdn.net/md/?articleId132214798 二、JQuery介绍 JQuery(JQ):JS的一个类库(方法库:包含了大量的、有助于项目开发的属性和方法) 第一代版本1.xx.xx: 1.11.3 兼容所有浏览器的࿰…...

初始爬虫9
1.元素定位后的操作 “find_element“仅仅能够获取元素,不能够直接获取其中的数据,如果需要获取数据需要使用以下方法”。下面列出了两个方法: 获取文本 element.text 通过定位获取的标签对象的 text 属性,获取文本内容 获取属性…...
从细胞到临床:表观组学分析技术在精准医疗中的角色
中国科学院等科研院所的顶尖人才发起,专注于多组学、互作组、生物医学等领域的研究与服务。在Nature等国际知名期刊发表多篇论文,提供实验整体打包、免费SCI论文润色等四大优势服务。在表观组学分析技术方面,提供DAP-seq、ATAC-seq、H3K4me3 …...

带你0到1之QT编程:二十、QT与MySQL喜结连理,构建数据库应用开发
此为QT编程的第二十谈!关注我,带你快速学习QT编程的学习路线! 每一篇的技术点都是很很重要!很重要!很重要!但不冗余! 我们通常采取总-分-总和生活化的讲解方式来阐述一个知识点! …...
梯度下降法及其性能评估
梯度下降法 梯度下降法是一种一阶迭代优化算法,用于寻找函数的局部最小值。在机器学习中,它通常用来最小化损失函数(也称为成本函数或误差函数),以提高模型对数据的拟合程度。梯度下降法的基本思想是沿着目标函数当前…...

906. 超级回文数
1. 题目 906. 超级回文数 2. 解题思路 题目意思很简单,在给定范围中找到所有满足,它本身是回文,且它的平方也是回文的数字个数。 这题需要注意题目给定的范围,后面很有用: 因为回文范围是有限的,那么我…...
代码随想录算法训练营||二叉树
前/中/后序遍历 递归方式 参考文章 题目 思路:其实递归方式的前中后序遍历的方式都差不多,区别是在父节点的遍历时间。 前序代码 class Solution {public List<Integer> preorderTraversal(TreeNode root) {List<Integer> result new…...

线上报名小程序怎么做
在这个数字化、智能化的时代,信息技术的发展正以前所未有的速度改变着我们的生活。无论是学习、工作还是娱乐,互联网都成为了我们不可或缺的一部分。而在线上报名这一领域,小程序的出现更是为广大用户带来了前所未有的便捷与高效。今天&#…...
【测试岗】手撕代码 - 零钱兑换
322. 零钱兑换 题目描述 给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。 你可以认为每种…...

菱形继承的类对父类的初始化、组合、多态、多态的原理等的介绍
文章目录 前言一、菱形继承的类对父类的初始化二、组合三、 多态1. 构成多态2. 虚函数3. 虚函数的重写4. 虚函数重写的两个例外1. 协变2. 析构函数的重写 5. C11 final 和 override1. final2. override 6. 设计不想被继承的类7. 重载、覆盖(重写)、 隐藏…...

Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...

通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...

佰力博科技与您探讨热释电测量的几种方法
热释电的测量主要涉及热释电系数的测定,这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中,积分电荷法最为常用,其原理是通过测量在电容器上积累的热释电电荷,从而确定热释电系数…...

人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...