跳转至

14 事件处理

一、什么是 VBA 中的事件?

事件(Event) 可以理解为: 某个对象发生了一个动作或状态变化,比如:

  • 用户点击了单元格
  • 修改了单元格内容
  • 打开或关闭了工作簿

这些动作,在 VBA 里都可以被捕获,并触发对应的代码执行。也就是说 事件 = 触发条件 + 自动执行的代码,常见如下:

动作 对应事件 动作 对应事件
点击单元格 SelectionChange 修改单元格 Change
打开文件 Workbook_Open 关闭文件 Workbook_BeforeClose

这些事件不需要手动运行宏,只要动作发生,代码就会执行。

二、VBA 事件的整体分类

在 Excel VBA 中,事件主要分为三大类:

  • 应用程序级事件(Application 级):作用范围是整个 Excel 应用程序,适合做全局监控、日志、统一控制

  • 工作簿事件(Workbook 级):作用范围是当前工作簿,需要写在 ThisWorkbook 模块中,不影响其他工作簿

  • 工作表事件(Worksheet 级):作用范围是某一张工作表,需要写在具体工作表对象中

可以参考如上图片,工作簿事件直接写在ThisWorkbook 模块,而工作表需要下拉选择worksheet

2.1 工作簿事件详解

1. Workbook_Open —— 打开工作簿时触发

当工作簿被打开完成后自动触发,一般写在 ThisWorkbook 模块中,常用于初始化变量,自动登录等

1
2
3
Private Sub Workbook_Open()
    MsgBox "欢迎使用本系统!"
End Sub
2. Workbook_BeforeClose —— 关闭前触发

用户关闭工作簿时,在真正关闭之前触发此事件,常用于防止误关闭、强制保存等

1
2
3
4
5
Private Sub Workbook_BeforeClose(Cancel As Boolean)
    If MsgBox("确定要关闭吗?", vbYesNo) = vbNo Then
        Cancel = True
    End If
End Sub
3. Workbook_SheetChange —— 任意工作表被修改

1
2
3
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
    Debug.Print "工作表:" & Sh.Name & " 被修改"
End Sub
在这里插入图片描述 需要注意的是,真正的事件有很多,可以在VBA编辑窗口下拉查看,下面给大家总结一些,列表如下:

事件名 功能说明
Workbook_Open 打开工作簿时触发,常用于初始化设置、欢迎提示、环境检查
Workbook_BeforeClose 关闭工作簿前触发,可用于确认是否关闭、强制保存数据
Workbook_Activate 工作簿被激活时触发(获得焦点)
Workbook_Deactivate 工作簿失去焦点时触发
Workbook_BeforeSave 保存前触发,可拦截保存或自定义保存逻辑
Workbook_AfterSave 保存完成后触发,可用于提示或记录保存日志
Workbook_NewSheet 新建工作表时触发
Workbook_SheetChange 任意工作表的单元格内容发生改变时触发
Workbook_SheetSelectionChange 任意工作表的选中区域发生变化时触发
Workbook_SheetActivate 任意工作表被激活时触发
Workbook_SheetDeactivate 任意工作表被切换离开时触发
Workbook_SheetBeforeDoubleClick 任意工作表单元格被双击前触发,可用于拦截默认编辑
Workbook_SheetBeforeRightClick 任意工作表右键单击前触发,可自定义右键行为
Workbook_WindowResize 工作簿窗口大小发生改变时触发
Workbook_WindowActivate 工作簿窗口被激活时触发
Workbook_WindowDeactivate 工作簿窗口失去焦点时触发

2.2 工作表事件详解

1. Worksheet_SelectionChange —— 选中单元格变化

只要选中区域发生变化就触发,常用于显示当前选中信息,制作简易聚光灯等

1
2
3
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    Me.Range("A1").Value = Target.Address
End Sub
2. Worksheet_Change —— 单元格内容发生改变

这是使用频率最高的事件之一,常用于自动填充,实时检验输入等

1
2
3
4
5
Private Sub Worksheet_Change(ByVal Target As Range)
    If Target.Column = 1 Then
        Target.Offset(0, 1).Value = Now
    End If
End Sub
但是需要注意一个问题:事件递归,如果你仅仅是想要响应用户的修改,而不是事件自己的修改,写法如下:

1
2
3
Application.EnableEvents = False
' 修改单元格
Application.EnableEvents = True

这样在事件对单元格修改时,不会再触发事件,能够避免死循环触发事件

3. Worksheet_Activate / Deactivate:sheet被激活或者失去焦点的时候触发,常用于提示信息

1
2
3
Private Sub Worksheet_Activate()
    MsgBox "进入该工作表"
End Sub
同样地,我把主要的一些工作表事件总结如下:

事件名 功能说明
Worksheet_Activate 工作表被激活(切换到该表)时触发
Worksheet_Deactivate 工作表被切换离开时触发
Worksheet_SelectionChange 工作表中选中单元格或区域发生变化时触发
Worksheet_Change 工作表中单元格内容发生改变时触发(最常用)
Worksheet_BeforeDoubleClick 单元格被双击前触发,可拦截默认编辑行为
Worksheet_BeforeRightClick 单元格被右键单击前触发,可自定义右键菜单
Worksheet_Calculate 工作表重新计算时触发(公式结果变化)
Worksheet_FollowHyperlink 单击工作表中的超链接时触发
Worksheet_PivotTableUpdate 该表中的数据透视表刷新完成后触发
Worksheet_ChangeChart 工作表中图表数据发生变化时触发(较少使用)

2.3 应用程序级事件

这是进阶玩法,需要搭配类模块使用,用的不多,但是对于有些需求是: 不管哪个工作簿、哪个工作表,只要发生某事,就处理,例如:记录所有修改日志、监控用户操作、统一拦截打开文件等,这个就能派上用场,因此只做简单示范:

1
2
3
4
5
6
' 类模块:clsAppEvent
Public WithEvents App As Application

Private Sub App_WorkbookOpen(ByVal Wb As Workbook)
    MsgBox "打开了:" & Wb.Name
End Sub

定义上述类模块后,我们可以在普通模块中初始化,实现应用级的监听:

1
2
3
4
5
Dim AppEvent As New clsAppEvent

Sub StartListen()
    Set AppEvent.App = Application
End Sub

学会VBA事件之后,我们就可以 实现 自动记录修改时间限制用户输入等多样化的要求,也就是说 事件让 Excel 从“被动执行宏”,变成“主动响应用户行为”。