关于对象
第七篇、Excel VBA对象类型之:WorkSheet(工作表)对象
接上一篇:如何操控单元格对象?①找到符合要求的单元格、②改变它的状态、③改变它的特性,让它服从我们的需求。就是通篇我们围绕的三个重点:
- ①单元格对象的引用
- ②单元格对象的方法
- ③单元格对象的属性
沿着Excel对象的层级结构图往上,Range单元格的父对象是:Worksheet(单个工作表),Worksheet属于Worksheets (所有工作表的集合)。
本篇幅我们了解Worksheet工作表 和 Worksheets 工作表集合,来看这个对象的引用和操作,最后在结合Range单元格对象,看Worksheet + Range能给我们的日常工作带来多大的便利!
对象层级结构
通过Excel对象的层级结构图,看到Excel对象模型是一个树状结构,从顶层的 Application 开始,逐级向下延伸:
Application
│
├─ Workbooks (所有打开的工作簿集合)
│ │
│ └─ Workbook (单个工作簿)
│ │
│ ├─ Worksheets (所有工作表集合) 'Worksheet父对象
│ │ │
│ │ └─ Worksheet (单个工作表) 'Range的父对象
│ │ │
│ │ ├─ Range (单元格及区域)'Worksheet子对象
│ │ │
│ │ ├─ ChartObjects (嵌入的图表集合)
│ │ │ └─ ChartObject → Chart (嵌入的图表)
│ │ │
│ │ └─ Shapes (形状/图形集合,如文本框、图片等)
│ │ └─ Shape (单个形状)
│ │
│ └─ Charts (独立的图表工作表集合)
│ └─ Chart (独立的图表工作表)
│
└─ Windows (所有窗口集合)
上一篇了解🔗Range(单元格)对象,我们往上一级了解,这篇来看它的父对象Worksheet是如何工作的。
WorkSheet工作表对象
我们需要把WorkSheeets和WorkSheet放到一起来了解。WorkSheeets是WorkSheet的集合,把它当做WorkSheet的父辈就完事了,一个父亲可能有一个孩子WorkSheets(1),也可能有多个孩子WorkSheets(1)、WorkSheets(2)、WorkSheets(3).....。
Worksheets集合,常常用于批量操作多个工作表,你可以遍历它、添加表、删除表、复制表、隐藏表等等。
Worksheet是其中的一个成员(一个孩子),常常用于操作工作表的具体内容,你可以读写表格里的单元格数据、修改工作表的名称等等。
它俩一个是处理多个工作表的批量操作,一个是处理单个工作表的具体内容。
1-工作表对象的引用:
一样的:如果我们要操控工作表,首先也是要先选定(引用)它。同样作为的Excel VBA对象,工作表对象的引用比单元格对象简单太多了!单元格对象引用方法多的需要列出表来了解,直接引用、扩展引用、相对定位.....,工作表对象就两个:使用工作表名称或使用工作表的索引号。(可能还有一个:引用活动工作表-ActiveSheet)。
本节视频:
通过工作表名称引用
就是直接使用工作表的名称(字符串),我们每一个工作薄里都有多个(至少一个)工作表,每添加一个工作表,默认的名称是Sheet + 累计增加的数量,这个就是默认的工作表名称,我们引用它时,直接用:WorkSheets("Sheet1")即可,就表示引用了这个工作表。当我们自定义工作表名后,引用自定义的工作表名,也表示引用了这个工作表:WorkSheets("新名字"),就这么简单。
示例:
- 通过名称引用:
Sub 工作表引用_通过名称引用()
Worksheets("Sheet1").Range("B1").Value = "Hello,工作表"
Worksheets("表2").Range("B1").Value = "Hello,工作表"
End Sub
通过索引(位置)引用
就是通过工作表在集合(当前工作薄中的所有Worksheet)中的位置(索引)引用,索引是从1开始的。引用方式:Worksheets(1)。
这种引用方式有个缺点,索引程序会随着移动工作表而改变,不够稳定,比如原来名称为Sheet3工作表在第三个位置,索引值是3:Worksheets(3)可以引用它,移动到第四个位置后,索引值变成4。这时Worksheets(3)不能在引用这个工作表,而是Worksheets(4)。
示例
- 通过索引引用:
Sub 工作表引用_通过索引引用()
Worksheets(1).Range("C1").Value = "Hello,工作表索引"
’尝试改变第二个工作表的位置,在引用并写入内容试试
Worksheets(2).Range("C1").Value = "Hello,工作表索引"
End Sub
还有一种ActiveSheet引用,表示选中当前用户选中的工作表
ActiveSheet.Range("A1").value = 1,即表示当前的工作薄中那个工作表处于活动状态,就在这个工作表的A1单元格写入1。如果切换了活动工作表,代码可能会操作错误的对象。
2-工作表对象的操作(方法和属性):
单元格对象有自己的方法和属性,工作表对象也是!方法也是改变对象的状态,属性用来反映对象的特性。
和介绍Range单元格对象不同,既然已经了解了对象方法和属性用来做什么,在介绍新的对象时,我们先把该对象的一些方法和属性列出来,在通过示例来了解他们是如何工作的!
工作表对象的方法
常用方法列表:
工作表对象的属性
介绍Range单元格对象的属性时,提到过有些属性共有的(有相同的属性名可能含义和用法不同),也列举了一些共有、独有的属性名和用法。
这里我们仍把属于工作表对象常用的属性依次介绍下,不在说明它的共有的还是独有的,只知道它能用在工作表对象上表现它的特征就可以了。
常用属性列表:
关于Range、Cells、Usedrange等,是不是觉得很熟悉?,它们其实也就是上一节提到的“单元格的引用”,只不过我们是引用时一直用的是“本表”,也就是当前的、活动的WorkSheet工作表,可以用Range("A1")、Cells(1,1)这样直接引用。当它具体指向某个工作表时,具体写法就会是:WorkSheets("表1").Range("A1")、WorkSheets("表1").Cells(1,1),指定工作表.属性。
本节视频:
示例:
- 工作表对象的方法和属性:
Sub 工作对象的方法和属性()
'Add方法添加新工作表,Name设置并获取工作表名
Worksheets.Add After:=Worksheets(1) '添加新工作表
Worksheets(2).Range("A1").Value = Worksheets(2).Name '新工作表的A1单元格获取工作表名(默认)
Worksheets(2).Name = "新工作表1" '设置新的工作表名
Worksheets("新工作表1").Range("B1").Value = Worksheets("新工作表1").Name '新工作表的B1单元格获取新工作表名
Dim new_sht As Worksheet
Set new_sht = Worksheets.Add(After:=Worksheets(1)) 'set 将添加的新工作表赋值给一个变量,然后重命名
new_sht.Name = "新工作表2"
new_sht.Range("A1").Value = new_sht.Name
'删除工作表
Worksheets(2).Delete
Worksheets("新工作表1").Delete
'复制工作表
Worksheets(1).Copy After:=Worksheets(3)
Worksheets("Sheet1").Copy Before:=Worksheets(3)
'移动工作表位置
Worksheets(1).Move After:=Worksheets(3)
Worksheets("Sheet1").Move Before:=Worksheets(3)
'激活工作表
Worksheets(1).Activate
Worksheets("Sheet1").Activate
'Count属性,工作表的数量
MsgBox "当前工作薄中有: " & Worksheets.Count & "个工作表"
'Visible属性 工作表可见性
Debug.Print Worksheets("Sheet1").Visible '立即窗口输出Sheet1工作表的可见性
Worksheets("Sheet1").Visible = False '设置Sheet1工作表不可见(隐藏)
Debug.Print Worksheets("Sheet1").Visible
Worksheets("Sheet1").Visible = True
End Sub
3-了解几个常用的工作表事件
首先要确定下工作表事件的基本概念,从模块中存放代码说起”!
迄今为止,我们的代码一直被放置在“模块”中“代码窗口”的,因为我们默认代码就是用来“操控Excel各种对象,按照我们的设想完成自动化处理工作。”,代码不与任何的一个工作表特定关联,它是可以用来处理所有的工作表而不是某个特定的工作表。所以我们把它放在到“模块”中,“模块”是一个独立的代码文件。
工作表WorkSheet也可以用来存放代码,它同样也有“代码窗口”,只不过代码仅仅适用于存放的工作表”🔗代码的作用域和生命周期,它需要和工作表里的其他元素紧密集成来完成某个任务。
工作表事件,就是存放在工作表中的代码,它仅仅适用于存放的工作表,还有一个特性是:它伴随着工作表内的指定操作而自动触发程序。比如修改单元格内容时、激活当前工作表时或双击单元格时,就会自动触发代码(代码内容由开发者自己决定)。这对于增强工作表交互性和自动化功能特别有帮助。
本节视频:
示例1:
- 比如我们选定某一个单元格,希望整行和整列都高亮显示,用一个工作表事件就再也合适不过。只有在某个工作表里,选中单元格时才会出现这种效果!
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Cells.Interior.Color = RGB(255, 255, 255) '底色为白色
Target.EntireColumn.Interior.Color = RGB(255, 255, 0) '选中单元格的整列设置底色
Target.EntireRow.Interior.Color = RGB(255, 255, 0) '选中单元格的整行设置底色
End Sub
- 以上代码就是一个工作表的SelectionChange事件,当选择的单元格发生变化时触发执行的代码,代码段是“选中的单元格整行和整列显示黄色 RGB(255, 255, 0)”。
工作表事件有很多,打开进入Visual Basic编辑器,双击工程资源管理器中的一个工作表对象,在代码窗口顶端选择“WorkSheet",就进入了工作表事件,有很多种工作表事件,我们结合示例简单介绍几个常用的,知道在哪里?有什么作用?很重要!,至于如何用?,逢山开路、遇水架桥、查找资料!!
工作表事件选择:
几个常用的工作表事件:Change事件、SelectionChange事件、Activate事件:
- SelectionChange事件,当选择的单元格发生变化时触发执行的代码,我们已经通过示例介绍过,举了“动态提示、高亮显示”的例子。
- Change事件:单元格内容修改时触发代码,
- Activate事件:工作表被激活时触发代码。
假如,Sheets("表2")工作表的B3:H8区域存放着重要信息,每次修改都需要在A1单元格记录最后一次修改时间,A2单元格记录最后一次的工作表被激活时间(查看该工作表的时间),如何利用工作表事件?
示例2:
Private Sub Worksheet_Change(ByVal Target As Range)
'记录单元格B3:H8区域更内容的时间
If Not Intersect(Target, Range("B3:H8")) Is Nothing Then
Application.EnableAnimations = False '防止递归触发
Range("A1").Value = "最后修改时间: " & Now
Application.EnableAnimations = True
End If
End Sub
Private Sub Worksheet_Activate()
'当前工作表被激活时,在A2单元格写入激活时间
Range("A2").Value = "最后查看时间: " & Now
End Sub
- 1.Private:模块级的私有变量;
- 2.Worksheet_Change:工作表的Change事件,单元格内容修改时触发代码;
- 3.(ByVal Target As Range):ByVal表示按值传递参数,Target是一个Range对象,代表用户选定或操作的单元格范围;
- 4.If Not Intersect(Target, Range("B3:H8")) Is Nothing:
- Intersect两个单元格区域的交叉区域;
- Intersect(Target, Range("B3:H8")) Is Nothing两个单元格区域的相交区域为空;
- 整行的释义是:如果选定操作的单元格范围和Rnage("B3:H8")单元格区域有相交(不为空)。
- 5.Application.EnableAnimations = False '防止递归触发:防止第一次修改自动触发了某个操作,操作内容是修改,又触发了操作,这样陷入死亡递归。
- 6.Application.EnableAnimations = True:把禁用的在解放回来
- 7.Worksheet_Activate:工作表的Activate事件
4-工作表和数据处理(Worksheet + Range对象)
截止到现在我们已经了解过Excel VBA对象类型里的工作表对象、和单元格对象,这是最基础的也是尤为重要的两个,它们两个组合在一起,起码能解决我们办公自动化需求里的66%的问题!
可能您对这些个还没概念,觉得平平无奇,看了内容看了也就看了,但是它能用来做什么?怎么就能解决我的问题了?除非是你日常的工作还不需要用大量的时间去处理固定的表格,或是还不能按照设想把代码堆积起来解决问题!
这里通过我的经历、和最开始遇到的一个需要VB解决的问题作为示例,通过这个就能解释为什么“VB是编程零基础也能快速掌握,了解小部分知识点就能对工作带来很多便利, 拯救天选打工人的神器!。”
我的经历:合并工作表
- 2006年—2010年毕业最初的四年在一个鞋类的工厂做“生管”,就是生产计划和跟单,需要对从外贸接单到出货的整个过程制定详细的计划表,大致就是从物料采购、样本开发制作、确认、试产、排产、包装到交付,制定一个详细的计划表并跟进。这个期间逐渐熟悉了Excel表格,比如函数运用、数据透视、常规图表制作。以为电子表格的功能也就这些了,没有解决不了的问题,后来才发现不是没有问题,而是没有遇到更好的问题。
- 2011年跳槽至一家代工转自创品牌的服装企业做商品管理,工作内容包括:1、指导和服务加盟商做订销指引,2、负责集团直营店的商品流转(订货、铺货、促销、换季调整等全流程的货品管理)。第一次秋冬产品订货会,认知被彻底打破了。因为团队每天晚上需要复盘订货目标的完成进度,从客户的维度需要细分到每个加盟店、每个区域的完成量,从产品维度需要汇总每个品类、款式的订货量和尺码分布。这关联着前端的面料采购,面料采购单的早晚意味着成本和交期,毕竟同时段的可不止一个成衣公司在面对着面料供应商,这就需要每晚汇总所有的订货信息来做透视分析。
- 信息采集方式还算好,一个终端客户一个手持终端采集PDI设备。数据质量和完整度不用担心了,问题恰恰就出现在汇总上。当时也是第一次通过这种方式来采集信息(相比其他发展的早的品牌就太落伍了),PDI设备和后端的分析功能在当时是拆开来卖钱的这个谁又能懂?,公司就只用了设备和统计,就是记录和汇出,每晚结束后,需要要导出一个包含张三、李四、王五、赵六...等等多个工作表的工作薄,一个表就代表一个手持终端(加盟店),要知道先要汇总才能分析。这个汇总工作可太麻烦了!当时的新团队,也没人知道如何快速把80+张表的工作表汇总到一起。我就用了最原始的方式:建一个名为“汇总”的表、手动复制表、粘贴到汇总表里、第一列填充表名(加盟店名)、80+次重复,这个过程是真累、时间是真紧张。结束后自己复盘工作,唯独觉得这个过程不美丽,这么重复的占用大量时间的工作不能说毫无意义,是十分枯燥!
- 网上查找解决办法,印象最深的排名第一的解决办法是别人写的一个工具《逸凡工作簿合并助手》,惊为天人!界面友好、功能强大、使用了窗体和控件供多种方式的合并,但是收费,用自己的钱解决公司的问题不是我上班的原则,且当时只能解决这一个使用频次很低的问题!
- 既然了解了就想去尝试,如果也能解决日常工作中的高频问题就好了。“VBA代码合并工作表”就是手搓出的第一个满足自己个性化需求的小段代码,过程很痛苦。一本厚厚的《Visual Basic编程基础》从头看到尾,似懂非懂,知识点太多!转念想:“我就想解决现实的这一个小问题,先解决它就可以了,其他的管它呢,又不准备做是专业开发者和老师。”,这就又从头开始,看到Worksheet和Range对象就有了点眉目了,就觉得似乎找到办法了:就是操作工作表和单元格嘛!
背景介绍就到这,从此就开始进入了遇到问题找解决方法的过程!
本节视频:
思路:
- 1、在第一个工作表之前,建一个名为“汇总”的工作表;
- 2、复制Sheet1,在“汇总”表的B列单元格开始粘贴;
- 3、在“汇总”表的第一列A列,从首个单元格开始到最后一行,写上Sheet1(来源表的名称)
- 4、复制Sheet2工作表的内容,接着"汇总"表的最后一行的下一行开始粘贴,然后同样写上Shee2的名称
- 5、重复 2 -3步骤,直到汇总完成。
开始堆代码,第一步手动新建“汇总”工作表,刚开始代码宁可少写,就担心出错!
Sub VBA代码合并工作表()
Dim sht As Worksheet
Dim end_row As Long, step_row As Long
'遍历这个工作薄的每一个工作表
For Each sht In Worksheets
'先判断“汇总”工作表的已使用区域的最后一行是哪里,增加一行用来存放下复制的工作表
end_row = Sheets("汇总").UsedRange.Rows.Count + 1
'复制工作表,粘贴到“汇总”里的B列,位置就是已使用区域的下一行
sht.UsedRange.Copy Destination:=Sheets("汇总").Range("B" & end_row)
'计算出复制的工作表的行数
step_row = sht.UsedRange.Rows.Count
'在“汇总表”的A列,从最后一行开始,到复制的行数为止,写入复制的工作表名
Sheets("汇总").Range("A" & end_row & ":A" & end_row + step_row).Value = sht.Name
Next
End Sub
以上不包括定义和类型注释语句,只有6行,一个循环、一个计算、一个复制粘贴就搞定了~~。结果如下图(至于为什么首列还有多出2行,这个就不重要了),运行不出错还能返回正确的结果,就是有用的代码,剩余的用表格知识:筛选+剔除就OK了。这就是我的第一个解决实际问题的程序,简单吧?~
不复杂的工作经历告诉我,工作表对象+单元格对象组合在一起,起码能解决办公自动化需求里的66%的问题!
下一篇:了解Excel VBA的对象之:Workbook(工作簿)对象
通过不同用方式的组合运用,找到单元格并选定他们,通过方法(操作)和属性(设置),让单元根据我们的要求做出相应的改变。这就是操控单元格对象!
通过工作表名称或索引(位置)引用工作表,用它的方法和属性,让工作表根据我们的要求做出相应的改变,这就是操控工作表对象!
工作表对象+单元格对象组合已然能解决很多的、在一个工作薄内的问题,如果跨工作薄呢?延续本篇的案例:如果每个小组是一个工作簿,有10个小组管理这80+门店,就意味着有10个工作簿内、合计包含80个工作表,如何汇总呢?
沿着“对象的层级结构”在往上一级了解,就是WorkBook(工作薄)对象!
请开发者喝杯咖啡!