从0学Excel VBA编程 第12篇:事件编程——让代码"自动触发"
学习目标
理解什么是事件,知道事件代码写在哪里 掌握 Workbook_Open 和 Worksheet_Change 两个最常用的事件 学会用 EnableEvents 防止事件"无限循环"
知识点精讲
从第1篇到第11篇,我们写的所有代码都有一个共同点——必须手动按 F5 才能运行。
这一篇,我们要学一种全新的方式:事件(Event)。
事件就是——当某个操作发生时,代码自动运行。不需要你按 F5,不需要你点任何按钮,Excel 会自己"感应"到操作并执行对应的代码。
生活中的事件类比
想象一下自动门:你走过去,门自动开了。你不需要按开关,门上有个传感器,检测到人靠近就自动开门。事件就是这个"传感器"。
在 Excel 里:
打开文件 → 自动触发 Workbook_Open事件修改单元格 → 自动触发 Worksheet_Change事件关闭文件 → 自动触发 Workbook_BeforeClose事件
事件代码写在哪里?(关键!)
这是本篇最重要的知识点。事件代码不能写在普通模块里,必须写在特定位置:
注意: 如果你把事件代码写在了普通模块(Module1)里,它不会自动触发,写了等于白写。
事件过程的样子
普通过程长这样:
Sub 我的宏() ' 代码内容End Sub事件过程长这样:
Private Sub Worksheet_Change(ByVal Target As Range) ' 代码内容End Sub区别有两点:
多了 Private——表示这个过程只能在当前模块里用,不会出现在宏列表里过程名是固定的—— Worksheet_Change是 Excel 规定的名字,一个字都不能改,改了就不触发了括号里有 ByVal Target As Range——这是 Excel 传给你的参数,告诉你是哪个单元格被改了
Target 参数详解
当用户修改了某个单元格,Excel 会自动把那个单元格作为 Target 传给事件过程。
Target.Column ' 被修改的单元格在第几列(1=A列,2=B列,3=C列)Target.Row ' 被修改的单元格在第几行Target.Value ' 被修改后的新值Target.Offset(0, 1) ' 同一行、右边一列的单元格(Offset 表示偏移)Offset(行偏移, 列偏移) 是一个很方便的用法:
Offset(0, 1)= 同一行,往右1列Offset(1, 0)= 往下1行,同一列Offset(-1, 0)= 往上1行,同一列
EnableEvents:防止无限循环(必学!)
Worksheet_Change 会在单元格被修改时触发。但如果你的事件代码本身也在修改单元格,会怎样?
修改单元格 → 触发事件 → 事件代码修改单元格 → 再次触发事件 → 再次修改……
这就是"无限循环",Excel 会卡死。
解决办法:在修改单元格之前,用 Application.EnableEvents = False 暂时关闭事件感应,改完之后再 = True 恢复。
Application.EnableEvents = False ' 关闭事件感应Target.Offset(0, 1).Value = Now ' 修改单元格(不会触发事件)Application.EnableEvents = True ' 恢复事件感应记住这个三步走:关闭 → 操作 → 恢复,缺一不可。
实战案例
案例 1(简单):打开文件自动显示欢迎信息
功能说明: 当用户打开这个 Excel 文件时,自动弹出一个欢迎框,显示今天的日期和文件名。
Private Sub Workbook_Open() MsgBox "欢迎使用本工作簿!" & vbCrLf & _ "今天是 " & Format(Date, "yyyy年mm月dd日") & vbCrLf & _ "文件名:" & ThisWorkbook.Name, _ vbInformation, "欢迎"End Sub操作步骤:
按 Alt + F11打开 VBA 编辑器在左侧工程管理器中,双击 ThisWorkbook(不是右键插入模块!) 在右侧代码窗口顶部,确认左下拉框显示 (General),右下拉框显示(Declarations)从左下拉框选择 Workbook,Excel 会自动帮你写好Private Sub Workbook_Open()的框架在框架内填入上面的代码 保存文件(必须保存为 .xlsm 格式,即"Excel 启用宏的工作簿") 关闭文件,重新打开——欢迎信息会自动弹出!
代码解释:
Private Sub Workbook_Open():这是工作簿"打开时"的事件,名字固定不能改Format(Date, "yyyy年mm月dd日"):把今天日期格式化成"2026年08月14日"这种中文格式ThisWorkbook.Name:当前文件的文件名vbInformation:消息框上显示一个蓝色"i"信息图标vbCrLf:换行符,让消息框里分多行显示
案例 2(中等):编辑 A 列自动在 B 列记录时间
功能说明: 当你在 A 列(从第2行开始)输入任何内容时,B 列自动写入当前时间,省去手动打时间的麻烦。
Private Sub Worksheet_Change(ByVal Target As Range) ' 只关心 A 列(第1列),且从第2行开始(跳过第1行标题) If Target.Column = 1 And Target.Row > 1 Then ' 暂时关闭事件,防止改 B 列时再次触发 Application.EnableEvents = False ' 在同行 B 列写入当前时间 Target.Offset(0, 1).Value = Format(Now, "hh:nn:ss") ' 重新开启事件 Application.EnableEvents = True End IfEnd Sub操作步骤:
按 Alt + F11打开 VBA 编辑器在左侧工程管理器中,双击 Sheet1(不是插入模块!) 从左下拉框选择 Worksheet,Excel 会自动帮你写好事件框架从右下拉框选择 Change,Excel 会生成Private Sub Worksheet_Change的框架在框架内填入上面的代码 回到 Excel,在 A1 单元格写上"任务名称"作为标题 在 A2 单元格输入任意内容(比如"写报告"),按回车 看 B2 单元格——自动出现了当前时间!
代码解释:
ByVal Target As Range:Excel 自动传进来的参数,就是被修改的那个单元格Target.Column = 1:判断被修改的单元格是否在 A 列(第1列)Target.Row > 1:跳过第1行(标题行)Application.EnableEvents = False:关闭事件感应,这样写 B 列时不会再触发事件Target.Offset(0, 1).Value = ...:Offset(0, 1) 表示同一行往右1列,即 B 列,写入当前时间Format(Now, "hh:nn:ss"):把当前时间格式化为"14:30:25"这样的格式Application.EnableEvents = True:恢复事件感应,别忘了这一步!
如果把 EnableEvents 那两行去掉会怎样? 你在 A 列输入内容 → 触发事件 → 事件往 B 列写时间 → B 列被修改又触发事件 → 事件又往 B 列写时间 → 又触发……Excel 直接卡死。这就是为什么 EnableEvents 必须要加。
案例 3(实用小案例):输入状态自动变色
功能说明: 在 C 列输入任务状态时,单元格自动变色——"完成"变绿色、"进行中"变黄色、"待处理"变红色,其他内容清除颜色。一目了然,不用手动设置格式。
Private Sub Worksheet_Change(ByVal Target As Range) ' 只关心 C 列(第3列),且从第2行开始 If Target.Column = 3 And Target.Row > 1 Then Application.EnableEvents = False Dim 状态 As String 状态 = Target.Value If 状态 = "完成" Then Target.Interior.Color = RGB(200, 255, 200) ElseIf 状态 = "进行中" Then Target.Interior.Color = RGB(255, 255, 200) ElseIf 状态 = "待处理" Then Target.Interior.Color = RGB(255, 200, 200) Else Target.Interior.ColorIndex = xlNone End If Application.EnableEvents = True End IfEnd Sub操作步骤:
按 Alt + F11打开 VBA 编辑器双击左侧的 Sheet1(如果案例2已经写在这了,就把代码接在下面——一个工作表可以有多个事件过程) 如果案例2已经用了 Worksheet_Change,你需要把案例3的逻辑合并到同一个Worksheet_Change里(Excel 只认一个)合并后的代码如下方"合并版"所示 回到 Excel,在 C1 写上"状态"做标题 在 C2 输入"完成"→ 变绿;C3 输入"进行中"→ 变黄;C4 输入"待处理"→ 变红 输入其他内容 → 颜色自动清除
如果案例2和案例3都要用,合并版代码:
Private Sub Worksheet_Change(ByVal Target As Range) Application.EnableEvents = False ' A 列:自动记录时间到 B 列 If Target.Column = 1 And Target.Row > 1 Then Target.Offset(0, 1).Value = Format(Now, "hh:nn:ss") End If ' C 列:自动变色 If Target.Column = 3 And Target.Row > 1 Then Dim 状态 As String 状态 = Target.Value If 状态 = "完成" Then Target.Interior.Color = RGB(200, 255, 200) ElseIf 状态 = "进行中" Then Target.Interior.Color = RGB(255, 255, 200) ElseIf 状态 = "待处理" Then Target.Interior.Color = RGB(255, 200, 200) Else Target.Interior.ColorIndex = xlNone End If End If Application.EnableEvents = TrueEnd Sub代码解释:
Target.Interior.Color = RGB(200, 255, 200):用 RGB 函数设置背景色,三个数字分别是红、绿、蓝,范围 0-255RGB(200, 255, 200):红色少、绿色多 → 浅绿色RGB(255, 255, 200):红绿都多、蓝少 → 浅黄色RGB(255, 200, 200):红色多、绿蓝少 → 浅红色Target.Interior.ColorIndex = xlNone:清除背景色,xlNone是 Excel 的内置常量,表示"无颜色"
本篇小结
今天我们学的是 VBA 的一个重要进阶能力——事件编程:
事件 = 自动触发:不需要按 F5,操作发生时代码自动运行 代码位置很重要:工作簿事件写在 ThisWorkbook,工作表事件写在对应工作表,写错地方就不触发 Workbook_Open:文件打开时自动执行,适合做欢迎提示、初始化设置 Worksheet_Change:单元格被修改时自动执行,适合做自动填表、数据验证、自动变色 Target 参数:告诉你哪个单元格被改了,用 .Column、.Row、.Value获取信息EnableEvents 三步走:关闭 → 操作 → 恢复,防止事件无限循环
重要提醒: 事件代码需要把文件保存为 .xlsm 格式(Excel 启用宏的工作簿)。如果保存为普通 .xlsx 格式,所有宏代码都会丢失。
下一篇内容预告
第 13 篇:自定义函数——打造你专属的公式
到目前为止,我们写的都是 Sub 过程——"做事型"代码,运行完就结束了。下一篇我们要学 Function——"计算型"代码,它能像 Excel 公式一样返回一个结果,甚至可以在单元格里直接使用 =我的函数() 来调用。掌握 Function,你就能自己造公式了,敬请期待。

夜雨聆风