【2.使用VBA自动填充Excel工作表】

news2024/9/27 9:20:37

目录

  • 前言
  • 什么是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 String
    Public sourceSheetName As String
    Public targetFilePath As String
    Public dateToCheck As String
    
Sub UserForm_Initialize()
    UserForm1.Show '打开用户界面
End Sub

Sub CopyDataBasedOnDate() '定义函数  用户界面
    Dim wsSource As Worksheet '定义变量 Worksheet 是Excel中工作表的对象类型,表示单个工作表。源工作簿不用设置
    Dim wbTarget As Workbook  'Workbook 是Excel中工作簿的对象类型,表示整个Excel文件,包括所有的工作表。
    Dim lastRow As Long
    Dim targetRowA As Long
    Dim targetRowC As Long
    Dim 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 If
    On Error GoTo 0 '这行代码用于关闭之前启用的错误处理。在遇到错误时停止执行并显示错误消息。这行代码通常放在错误处理代码的最后,以确保错误处理的范围仅限于特定的代码块。



     ' ############获取源工作表的最后一行  这里可能要调
    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    '因为最后一行也是两行合并
    ' ##############遍历源工作表中的所有行  应该要换个判断条件或者方式 根据日期,直到下一个日期
    Dim i As Long
    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 - 1
                    Exit For
                End If
                
                
                If wsSource.Cells(j, "A").Value = dateToCheck Then '如果已经碰到下一个日期 比如同一天的 还有可能不是同一天的
                    i = j - 1 '节省遍历循环的时间 跳出循环
                    Exit For
                End If
                
                If 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 + 1
                End If
            Next j

        End If
    Next i
    


    ' ############保存并关闭目标工作簿
    wbTarget.Save
'    wbTarget.Close

    MsgBox "数据复制完成"
End Sub



UserForm1的代码

Sub dateToCheckCommandButton_Click()
    Sheet1.dateToCheck = dateToCheckTextBox.Text
End Sub

Sub sourceSheetNameCommandButton_Click()
    Sheet1.sourceSheetName = sourceSheetNameTextBox.Text ' 把文本框的内容赋值给源工作表名字变量
End Sub
Sub targetFilePathCommandButton_Click()
    Sheet1.targetFilePath = targetFilePathTextBox.Text
End Sub

Sub targetSheetNameCommandButton_Click()
    Sheet1.targetSheetName = targetSheetNameTextBox.Text ' 把文本框的内容赋值给目标工作表名字变量
End Sub

Sub 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 - 1
                    Exit For
                End If
                
                
                If wsSource.Cells(j, "A").Value = dateToCheck Then '如果已经碰到下一个日期 比如同一天的 还有可能不是同一天的
                    i = j - 1 '节省遍历循环的时间 跳出循环
                    Exit For
                End If
                
                If 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 + 1
                End If
            Next j

        End If
    Next i

我在源文件遍历日期的方法是从第一行查找到最后一行,如果遇到匹配的字符串,就再内嵌一个循环,因为一个日期内有很多数据需要一行行地复制过去,还要判断数据的有效性

这里解释一下
For j = i +3是因为序号那一行是两行合并,所以有效数据是日期+3行 ,j-i>13是因为一般来说一次送货不会超过十种货,也就是对应十行数据了

提升对单元格等对象的操作知识

可以看出我对对单元格本身不了解 内置函数和属性不熟 所以判断数据有效性的条件很抽象

功能升级

  • 目前可以实现在页面不关闭的情况下一次插入一天的对账信息,但是这样也不够快,要是能一次插入一个时间范围内的对账信息就好了,估计要新增很多判断逻辑,以及对字符串的一些操作处理(因为有时候你的源工作表不一定就是2024/8/31这样的数据),最好是再做一个控件。

  • 输入文件路径有点麻烦,尝试改进成浏览文件的方式选中。

  • 未来要加入判断插入的数据是否是已有数据的逻辑才行,否则会重复插入 而且最好能提示用户“重复插入了”

  • 从送货单复制的数据到对账单并不是会完美一一对应,因为对账单和送货单所需要的信息不一定是一一对应的,可能会多或者少或者顺序不对,还有一些比较奇葩的是粘贴的目标列合并了,所以要怎么匹配列去进行粘贴 是一个问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2164920.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

社区来稿丨一个真正意义上的实时多模态智能体框架,TEN Framework 为构建下一代 AI Agent 而生

本文由 RTE 开发者社区成员通过社区网站投稿提供,如果你也有与实时互动(Real-Time Engagement,RTE)相关的项目分享,欢迎访问网站 rtecommunity.dev 发布,优秀项目将会在公众号发布分享。 自从 OpenAI 展示了…

大数据毕业设计选题推荐-手机销售数据分析系统-Hive-Hadoop-Spark

✨作者主页:IT毕设梦工厂✨ 个人简介:曾从事计算机专业培训教学,擅长Java、Python、PHP、.NET、Node.js、GO、微信小程序、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇…

PINN机器学习登上Science正刊!热门buff叠满!11个创新思路get到就能发

今天我们来聊聊物理信息机器学习PIML。PINN大家都熟悉吧,毕竟研究热度就没下去过,这个热点其实就是PIML的一种典型代表。 PIML是一种融合了物理学与机器学习的创新技术,通过引入物理学的先验知识,来改进和优化机器学习模型的性能…

换脸黑科技FaceFusion 3.0(Windows Mac整合包)震撼来袭!

换脸黑科技FaceFusion 3.0(Windows & Mac整合包)震撼来袭! 各位魔法师们,准备好迎接 FaceFusion 3.0 的强势登场了吗?这款 AI 换脸神器经历了全面升级,功能更强大,效果更惊艳,操…

C++(引用、窄化、输入)

1. 引用 reference&#xff08;重点&#xff09; 1.1 基础使用 引用就是某个变量或常量的别名&#xff0c;对引用进行操作与操作原变量或常量完全相同。 #include <iostream>using namespace std;int main() {int a 1;int& b a; // b是a的引用b;cout << a &…

基于单片机的汽车防酒驾控制系统设计

本设计基于STC12C5A60S2单片机的汽车防酒驾系统&#xff0c;主要包括主控制器、酒精检测模块、显示模块、声光报警模块和语音播报模块等共同组成&#xff0c;从而实现了对车内酒精浓度进行采集&#xff0c;预防酒驾的发生。利用酒精检测传感器对车辆内人员呼出的气体进行酒精浓…

C盘满了怎么清理_C盘满了深度清理详细操作步骤(多种方法)

最近有很多网友问我&#xff0c;我电脑C盘满了怎么清理&#xff1f;说自己不敢乱清理&#xff0c;怕清了系统文件无法正常开机&#xff0c;今天小编就教大家C盘满了清理的详细操作步骤&#xff0c;按教程来不怕系统进不了系统了。 C盘满了清理流程&#xff1a; 清理系统产生的…

vue-pdf 实现pdf预览、高亮、分页、定位功能

vue-pdf 实现pdf预览、高亮、分页、定位功能&#xff08;基于vue2.0&#xff01;&#xff01;&#xff01;&#xff09; 前言一、实现步骤1.引入库2.示例代码3.触发高亮事件4.分页高亮5.跳转指定页面并高亮&#xff08;不分页&#xff09; 参考笔记&#xff08;重要&#xff09…

C# 面对对象基础 枚举,Enum.TryParse的使用

代码&#xff1a; using System; using System.Collections.Generic; using System.Dynamic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks;namespace Student_c_ {enum Week : int{Mon,Tus,Wed,Thu,Fri,Sat,Sun,}public cla…

微服务之服务保护

Sentinel引入Java项目中 一&#xff1a;安装Sentinel 官网地址&#xff1a;https://github.com/alibaba/Sentinel/releases 二&#xff1a;安装好后在sentinel-dashboard.jar所在目录运行终端 三&#xff1a;运行命令&#xff0c;端口自己指定 java -Dserver.port8090 -Dcs…

iPhone16新机到手,,这些操作都要设置好

iPhone16新机首批机子已经发货&#xff0c;陆陆续续都几到了买家们手中了&#xff0c;iPhone 16到手后&#xff0c;虽然没有严格意义上的“必须”设置&#xff0c;但有一些推荐设置可以帮助您更好地使用和保护设备&#xff0c;同时提升安全性和使用体验&#xff0c;让你的新iPh…

栈的深度解析:链式队列的实现

引言 队列是一种广泛应用于计算机科学的数据结构&#xff0c;具有先进先出&#xff08;FIFO&#xff09;的特性。在许多实际应用中&#xff0c;例如任务调度、缓冲区管理等&#xff0c;队列扮演着重要角色。本文将详细介绍队列的基本概念&#xff0c;并通过链表实现一个简单的…

初识Jenkins持续集成系统

随着软件开发复杂度的不断提高&#xff0c;团队成员之间如何更好地协同工作以确保软件开发的质量&#xff0c;已经慢慢成为开发过程中不可回避的问题。Jenkins 自动化部署可以解决集成、测试、部署等重复性的工作&#xff0c;工具集成的效率明显高于人工操作;并且持续集成可以更…

网络原理3-应用层(HTTP/HTTPS)

目录 DNSHTTP/HTTPSHTTP协议报文HTTP的方法请求报头、响应报头(header)状态码构造HTTP请求HTTPS 应用层是我们日常开发中最常用的一层&#xff0c;因为其他层&#xff1a;传输层、网络层、数据链路层、物理层这些都是操作系统和硬件、驱动已经实现好的&#xff0c;我们只能使用…

【Python】的语言基础学习方法 快速掌握! 源码可分享!

python语言基础 第一章 你好python 1.1安装python https://www.python.org/downloads/release/python-3104/ 自定义安装&#xff0c;全选 配置python的安装路径 验证&#xff1a;cmd输入python 1.2python解释器 解释器主要做了两件事&#xff1a; 翻译代码提交给计算机去运…

Linux 下安装mysql

1.检查之前是否安装过mysql rpm -qa | grep mysql 如果之前安装过&#xff0c;删除之前的安装包 rpm -e 安装包 如果没有&#xff0c;进行后续安装 2. 下载 MySQL :: Download MySQL Community Server (Archived Versions)https://downloads.mysql.com/archives/community/ 3…

plt常用函数介绍二

目录 fig.add_subplot()ax.set()plt.legend()plt.subplots_adjust()plt.suptitle()plt.grid() fig.add_subplot() fig.add_subplot() 是 Matplotlib 中 Figure 对象的方法&#xff0c;用于在图形中添加子图&#xff08;subplot&#xff09;。 其语法为&#xff1a; subplot(…

同声传译用什么软件最方便?推荐五款易用的同声传译软件

在国际贸易、国际会议及跨国合作项目中&#xff0c;语言障碍往往是沟通效率的一大挑战。 为了解决这个问题&#xff0c;同声传译免费软件应运而生&#xff0c;它们通过先进的技术实现了即时准确的语言转换&#xff0c;极大地促进了不同语言使用者间的交流与协作。 下面&#…

2025考研倒计时 考研时间公布了 你准备好复习冲刺了吗?

2025考研倒计时 考研时间公布了 你准备好复习冲刺了吗&#xff1f;今年的考研时间终于公布了&#xff1a; 正式报名时间2024.10.15-2024.10.28&#xff0c;初试时间12月21日&#xff0c;相信很多学子们已经做好冲刺的准备了。 在这关键的90天的时间内&#xff0c;如何做到时刻…

各种编程语言中有哪些共性?超详细+通俗易懂版!!!

各种编程语言中存在着一些共性&#xff0c;这些共性构成了编程语言的基础框架和设计原则。以下是这些共性的主要方面&#xff1a; 1. 遵循基本的编程原则 模块化&#xff1a;将程序划分为多个独立、可复用的模块&#xff0c;有助于降低程序的复杂度并提高可维护性。封装&#…