VBA-TG第5节|事件编程
最近更新:'2019-04-24'
- 工作簿事件介绍
- 工作表事件介绍
3.worksheet_SelectionChange
4.worksheet_change(Target)
1. 工作簿事件介绍
1.1常用事件简单了解
双击打开工作簿,就显示今天是谁的生日.那需要怎么样可以到达这个目的呢?
![](https://img.haomeiwen.com/i9945523/fc8db737b264e31f.gif)
达到这个目的,需要用到事件处理,什么叫事件处理呢?
![](https://img.haomeiwen.com/i9945523/0ebdc86583501afa.png)
首先要搞清楚,程序代码应该写在什么地方?事件处理要写在发生地.
![](https://img.haomeiwen.com/i9945523/623e2e3f1cbe08f0.png)
那么案例1是打开工作簿发生的事件.因此在工作簿写代码.
![](https://img.haomeiwen.com/i9945523/8ccc2e7e5806b1a8.png)
![](https://img.haomeiwen.com/i9945523/0a556cc1fc5e17c4.png)
那么VBA怎么知道关联在哪件事件上?
![](https://img.haomeiwen.com/i9945523/a9e89f26ace9ef6a.png)
需要知道子程序名称与工作簿事件相对应.
![](https://img.haomeiwen.com/i9945523/067e26c4640df934.png)
![](https://img.haomeiwen.com/i9945523/acd59d5f4655f55f.png)
事件编程的总结
![](https://img.haomeiwen.com/i9945523/083612ed18a4df24.png)
完整的代码如下:
Private Sub Workbook_Open()
Dim today As Date, d As Date, i As Long
today = Date
i = 6
Do While Trim(Cells(i, 2)) <> ""
d = Cells(i, 6)
If Month(d) = Month(today) And Day(d) = Day(today) Then
MsgBox "½ñÌìÊÇ" & Cells(i, 3) & Cells(i, 5) & "µÄÉúÈÕ"
End If
i = i + 1
Loop
End Sub
![](https://img.haomeiwen.com/i9945523/4d5dcc1fd4d5e52b.png)
那么多事件编程,不需要记忆,直接在编程窗口有对应的事件,如下方法:
![](https://img.haomeiwen.com/i9945523/44680668c55d0741.png)
1.2workbook_beforeclose
在窗口关闭之前,先运行这段程序,这段程序有什么用法呢? 如下:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
MsgBox "再加,别忘记备份数据!"
End Sub
![](https://img.haomeiwen.com/i9945523/6b3c3c5237c6452b.png)
代码显示的结果如下:
![](https://img.haomeiwen.com/i9945523/b768a6e6f06f689f.gif)
Cancel这个参数的作用是否取消关闭这个动作.如果是true,则取消关闭这个懂这个动作,换句话说就是禁止关闭.
![](https://img.haomeiwen.com/i9945523/c7106c3cce7cc19d.png)
把程序稍微修改一下,禁止关闭.
Private Sub Workbook_BeforeClose(Cancel As Boolean)
MsgBox "再见,别忘记备份数据!"
Cancel = True
End Sub
代码显示的最终结果如下:
![](https://img.haomeiwen.com/i9945523/a03a8ee8ef40544b.gif)
![](https://img.haomeiwen.com/i9945523/0d6dd34a1c07947d.png)
![](https://img.haomeiwen.com/i9945523/8f837a78f17f1956.png)
1.3workbook_newsheet
即新增一个工作表的时候自动运行的事件.
里面有个参数sh代表刚刚新建的工作表对象.
![](https://img.haomeiwen.com/i9945523/e9b5e625ba6d074c.png)
![](https://img.haomeiwen.com/i9945523/2eb1dc5ce676c1ef.png)
2. 工作表事件介绍
2.1Worksheet_SelectionChange
这个是vba最常用的工作表事件
![](https://img.haomeiwen.com/i9945523/3323ad557ed42754.png)
Worksheet_SelectionChange是做什么的呢?
![](https://img.haomeiwen.com/i9945523/db7ca04ad6d8743d.png)
Worksheet_SelectionChange有个参数叫做Target.
![](https://img.haomeiwen.com/i9945523/90729593527a659e.png)
运用方法如下:
案例1
用鼠标或键盘选中单元格,则会显示单元格的地址.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
MsgBox Target.Address
End Sub
代码显示的结果如下:
![](https://img.haomeiwen.com/i9945523/5413253526ec7d90.gif)
案例2
用鼠标或键盘选中单元格,则会显示单元格的背景色是红色.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Target.Interior.Color = vbRed
End Sub
![](https://img.haomeiwen.com/i9945523/9fe55a85f8094136.png)
代码显示的结果如下:
![](https://img.haomeiwen.com/i9945523/7648c4c0dd6dfb27.gif)
案例3
只是被选中单元格高亮
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Cells.Interior.Color = xlNone
Target.Interior.Color = vbRed
End Sub
![](https://img.haomeiwen.com/i9945523/1cd258ff92474ee7.png)
代码显示的最终结果如下:
![](https://img.haomeiwen.com/i9945523/2eeecf42fd9680b9.png)
![](https://img.haomeiwen.com/i9945523/50652a2b242a7a74.png)
案例4
选中的单元格行与列均有背景色
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Cells.Interior.Color = xlNone
Target.EntireRow.Interior.Color = vbRed
Target.EntireColumn.Interior.Color = vbRed
End Sub
![](https://img.haomeiwen.com/i9945523/1478bf35ae2f53e4.png)
代码显示的最终结果如下:
![](https://img.haomeiwen.com/i9945523/2178a533e6210def.gif)
案例5
如何在相关的工作表的事件互相调用
首先,在工作表对应的代码只能运行当前的工作表.比如sheet1的事件代码只能运行sheet1,不能运行在sheet2.如想运行在sheet2,必须编写相关的代码.
![](https://img.haomeiwen.com/i9945523/0b3039eaaa1ff52e.png)
如想调用其他工作表的代码,更简洁,需要运用模块的格式进行调用.
模块1的代码
Sub highlight(r As Range)
Cells.Interior.Color = xlNone
r.EntireRow.Interior.Color = vbRed
r.EntireColumn.Interior.Color = vbRed
End Sub
![](https://img.haomeiwen.com/i9945523/f2581d5af7d36172.png)
sheet2的代码如下:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Call 模块1.highlight(Target)
End Sub
![](https://img.haomeiwen.com/i9945523/025a2b1e0a15f3ac.png)
可以同时在sheet3...sheetn的代码的调用,调用显示的结果如下:
![](https://img.haomeiwen.com/i9945523/2178a533e6210def.gif)
![](https://img.haomeiwen.com/i9945523/6bc1a47d44636486.png)
变量和过程(函数)的作用域
![](https://img.haomeiwen.com/i9945523/cff116ae3ffa81fa.png)
如果将之前的案例5的模块1改成private,在调用的过程中就会报错
![](https://img.haomeiwen.com/i9945523/b3dc08f6561a2235.png)
![](https://img.haomeiwen.com/i9945523/300f688bfe37a506.png)
3.worksheet_SelectionChange
案例1
如果在E或者G列选中某个亲友,会直接显示B列(姓名)这一列相同内容的单元格.比如选择E列(亲友1)的郭靖,会在B列显示有郭靖的单元格.
![](https://img.haomeiwen.com/i9945523/ae9da70885b6fdf5.png)
![](https://img.haomeiwen.com/i9945523/2864e7965e4ce919.png)
注意:
如果用户选中多个单元格.一样可以引发worksheet_SelectionChange,而此时的worksheet_SelectionChange中的target参数不是代表一个单元格,而是选中的单元格构成的range区域.
![](https://img.haomeiwen.com/i9945523/cbd54a1fbaf6d9f5.png)
为了避免选中多个单元格带来困扰,因此对选中的单元格规定为选中区域的第一行第一列(即左上角第一个单元格)
![](https://img.haomeiwen.com/i9945523/10117ec938687f4a.png)
期望达到的效果是点击亲友列(即E列和G列),可以在B列显示相同内容的单元格.除了亲友列,其他单元格不应该做查找的工作.
我们可以写一个判断语句.
![](https://img.haomeiwen.com/i9945523/f0bcd571d01048a9.png)
那么又如何查找与r内容相同的单元格并被选中
![](https://img.haomeiwen.com/i9945523/1587c388fa36c4d2.png)
![](https://img.haomeiwen.com/i9945523/2547f49ecf4da6b6.png)
完整的代码如下:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim r As Range
Set r = Target.Cells(1, 1)
If r.Row > 3 And (r.Column = 5 Or r.Column = 7) Then
i = 4
Do While Trim(Cells(i, 2)) <> ""
If Trim(Cells(i, 2)) = Trim(r.Value) Then
Cells(i, 2).Select
Exit Do
End If
i = i + 1
Loop
End If
End Sub
![](https://img.haomeiwen.com/i9945523/70ea8e3866e52aee.png)
代码显示的结果如下:
![](https://img.haomeiwen.com/i9945523/aa0024cf4b367369.gif)
虽然完成了跳转,但是对亲友这两列无法对单元格的内容进行修改.方法有很多,以下方法是比较常用的方法.
在跳转之前进行咨询,确定是否跳转?
![](https://img.haomeiwen.com/i9945523/c34cb6c4843e6cdd.png)
![](https://img.haomeiwen.com/i9945523/b535c6d13601638c.png)
完整的代码:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim r As Range
Set r = Target.Cells(1, 1)
If r.Row > 3 And (r.Column = 5 Or r.Column = 7) Then
k = MsgBox("确定跳转?", vbYesNo)
If k = vbYes Then
i = 4
Do While Trim(Cells(i, 2)) <> ""
If Trim(Cells(i, 2)) = Trim(r.Value) Then
Cells(i, 2).Select
Exit Do
End If
i = i + 1
Loop
End If
End If
End Sub
![](https://img.haomeiwen.com/i9945523/b770bd348ec01d95.png)
代码显示的结果如下:
![](https://img.haomeiwen.com/i9945523/43c2f91d52f86951.gif)
4.worksheet_change(Target)
常用于修改单元格,一离开修改好的单元格就会激活change事件,并且运行相关代码.与此同时,即便是光标在单元格在里面闪烁,哪怕没做任何修改,一离开单元格,同样会激活change事件.千万不要被chang这个名字所迷惑.
change常用于修改的单元格的数值是否符合规定.相当于数据有效性的检验.
change也有个参数,叫target,代表的是刚刚修改过的单元格.
![](https://img.haomeiwen.com/i9945523/64b096a970e3f474.png)
案例1
要求武林世家社会网络分析中的武力值是0-100的数值.其他文本或者更大的数字就会出错.
![](https://img.haomeiwen.com/i9945523/58f278f05c7ac15b.png)
![](https://img.haomeiwen.com/i9945523/bafca230703f30e3.png)
完整的代码:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Row > 3 And Target.Column = 4 Then
If Not IsNumeric(Target) Or Target > 100 Or Target < 5 Then
MsgBox "武力值必须是0到100之间的数字!"
Target.Select
End If
End If
End Sub
![](https://img.haomeiwen.com/i9945523/500e0ef41e491a06.png)
代码显示的最终结果如下:
![](https://img.haomeiwen.com/i9945523/e19208d9023bddf3.gif)
change事件使用的时候要特别小心
并不是每一种单元格的修改都能激活change事件.
![](https://img.haomeiwen.com/i9945523/f8cebc857a775faf.png)
案例2
要求武林世家社会网络分析中的武力值是0-100的数值.其他文本或者更大的数字就会出错,并且单元格显示为"待输入"
在代码块增加一行代码:
Target.Value = "待输入"
![](https://img.haomeiwen.com/i9945523/173f1bca8a9d8037.png)
因为在运行VBA代码时,在VBA代码中修改了单元格的内容,导致激活了change事件.msgbox界面一直是打开状态.
![](https://img.haomeiwen.com/i9945523/b6856e5e98626ff5.png)
![](https://img.haomeiwen.com/i9945523/21e323e7e36aed2f.gif)
这种事件称为事件级联,应该要避免的一种情况.
![](https://img.haomeiwen.com/i9945523/be8652b09c40e2c3.png)
![](https://img.haomeiwen.com/i9945523/30af21e248bbc44a.png)
![](https://img.haomeiwen.com/i9945523/3afd810e1ba805fc.png)
完整的代码:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Row > 3 And Target.Column = 4 Then
If Not IsNumeric(Target) Or Target > 100 Or Target < 5 Then
MsgBox "武力值必须是0到100之间的数字!"
Target.Select
Application.EnableEvents = False
Target.Value = "待输入"
Application.EnableEvents = True
End If
End If
End Sub
![](https://img.haomeiwen.com/i9945523/58b1af6dd7dc794e.png)
代码显示的最终结果如下:
![](https://img.haomeiwen.com/i9945523/151b1158d6c1f3df.gif)