ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 9263|回复: 15

给Shape对象添加事件,实时监测对象变化

[复制链接]

TA的精华主题

TA的得分主题

发表于 2014-10-22 14:31 | 显示全部楼层 |阅读模式
本帖已被收录到知识树中,索引项:类和类模块
本帖最后由 wpxxsyzx 于 2014-10-22 14:35 编辑

    逛msdn,无意间发现CommandBars对象具有OnUpdata事件,其解释也很简单,就是工具栏更新时触发此事件。经测试,很多常用操作都会引起工具栏的更新,所以,可以利用这个事件实时监测用户是否对某些对象执行了操作,既某些对象是否发生变化,例如:选择、添加、删除Shape对象,更改工作表的顺序,使用鼠标滚轮滚动表格等(excel本身不为这些对象的变化提供相关的事件)。
    说在前面,说是给Shape对象添加事件,其实也可以给其他对象添加额外的事件来监测对象的变化;示例都写成类的形式,是为了方便演示和理解,其实也可以直接在代码中使用OnUpdata事件而不用写入类模块里。总之,本帖是为了介绍OnUpdata事件,示例没有全面考虑所有可能的情况,还有很多漏洞,仅仅是个介绍,有兴趣的朋友可以研究下,使之更完善或者实现更多的功能。
下面通过一个简单例子来认识一下OnUpdata事件,此示例监测显示比例是否变化,如果是,根据情况作出相应的调整。

1、添加一个类模块clsZoom,并输入以下声明
Public WithEvents cmdBars As CommandBars
Public Event Zoom(ByVal number As Integer)
    使用WithEvents声明变量cmdBars 为 CommandBars类型,WithEvents关键字用来引出CommandBars对象的事件:OnUpdata(这个事件也是CommandBars对象公开的唯一一个事件),并把事件添加到VBE编辑器“过程”列表框里。
    使用Event语句为类声明一个名字为Zoom的事件过程
2、在VBE编辑器界面依次单击“对象”列表框——“cmdBars”选项,为类添加“cmdBars_OnUpdate”事件。
3、依次单击“对象”列表框——“Class”选项——“过程”列表框——“Class”选项,为类添加初始化事件“Class_Initialize”。

完整的代码:
Public WithEvents cmdBars As CommandBars
Public Event Zoom(ByVal number As Integer)
Private Sub Class_Initialize()
    '将应用程序的CommandBars对象赋值给变量cmdBars,当用户在界面或使用代码操作excel时,
    '将会使CommandBars对象产生更新,触发cmdBars_OnUpdate事件
    Set cmdBars = Application.CommandBars
End Sub
Private Sub cmdBars_OnUpdate()
    If ActiveWindow.Zoom <> 100 Then
        '使用RaiseEvent语句触发Zoom事件并把当前窗口的显示比例作为参数传入
        RaiseEvent Zoom(ActiveWindow.Zoom)
    End If
End Sub
4、在ThisWorkbook模块添加以下代码:
Private WithEvents MyZoom As clsZoom
    使用WithEvents 声明变量MyZoom 为 clsZoom类型,引出我们在clsZoom类模块里使用Event语句声明的Zoom事件并添加到VBE编辑器“过程”列表框里。
5、依次单击“对象”列表框——“MyZoom”选项——“过程”列表框——“Zoom”选项,添加MyZoom_Zoom事件过程并输入代码。
Private Sub MyZoom_Zoom(ByVal number As Integer)
'在这里输入你的代码以实现在显示比例变化时想要的结果
    If number > 100 Or number < 80 Then
        ActiveWindow.Zoom = 100
    End If
End Sub
6、添加如下代码
Private Sub Workbook_Open()
    Set MyZoom = New clsZoom
End Sub
7、代码是如何工作的
     在打开工作薄时使用New关键字创建clsZoom类的实例并赋值给变量MyZoom,代码转到clsZoom类模块中的Private Sub Class_Initialize()事件过程中执行。当用户操作excel时将会触发clsZoom类模块中的Private Sub cmdBars_OnUpdate()事件过程,执行该过程中的代码,如果用户在界面修改或者使用代码修改了显示比例,则使用RaiseEvent语句触发 Zoom事件,代码转到ThisWorkbook模块中的Private Sub MyZoom_Zoom(ByVal number As Integer)事件过程中继续执行,如果显示比例不在规定范围内,则调整显示比例为100。

ZoomEvent.rar

8.95 KB, 下载次数: 202

评分

3

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-10-22 14:42 | 显示全部楼层
    回到帖子标题上来,给Shape对象添加事件。添加多个事件,分别监测是否选择、添加、删除、Shape对象以及是否改变Shape对象的位置和尺寸。没有考虑同时操作多个对象的情况,切换工作表等情况有兴趣的朋友可以完善一下。打开示例,添加、删除、选择Shape对象,改变对象位置或尺寸即可触发相应的事件。

类模块代码:
Public WithEvents CMDBars As Office.CommandBars
'以下5句代码声明5个事件
Public Event ShapeSelectChange(ByVal shp As Shape)
Public Event ShapeMove(ByVal shp As Shape)
Public Event ShapeResize(ByVal shp As Shape)
Public Event ShapesAdd(ByVal shp As Shape)
Public Event ShapesDelete(ByVal name As String)
'存储当前选择的Shape对象以及对象的位置、尺寸、名字
Private NowShape As Shape
Private Top As Single
Private Left As Single
Private Width As Single
Private Height As Single
Private name As String
'Names集合用来存储在添加、删除Shape对象前
'各个Shape对象的名称
Private Names As New Collection

Private Sub Class_Initialize()
    Set CMDBars = Application.CommandBars
    Set NowShape = GetShape()
    Call GetShapes
    If Not NowShape Is Nothing Then
        Top = NowShape.Top
        Left = NowShape.Left
        Width = NowShape.Width
        Height = NowShape.Height
        name = NowShape.name
    End If
End Sub
Private Sub CMDBars_OnUpdate()
    Set NowShape = GetShape()
    '如果当前选中的是Shape对象则将对象的5个属性值
    '赋值给5个变量,以备下次变化时做比对
    If NowShape Is Nothing Then
        name = ""
        Width = 0
    Else
        Call ShapeEvent
        Top = NowShape.Top
        Left = NowShape.Left
        Width = NowShape.Width
        Height = NowShape.Height
        name = NowShape.name
    End If
    Call ShapesEvent
    Call GetShapes
End Sub
Private Function GetShape() As Shape
    Dim shp As Shape
    Dim shprange As ShapeRange
    On Error Resume Next
        Set shprange = Application.Selection.ShapeRange
    If Not shprange Is Nothing Then Set shp = shprange.Item(1)
    Set GetShape = shp
End Function
Private Sub ShapeEvent()
    '如果当前选择的是Shape对象,并且名字和name变量里不一致
    '并且当前Sheets集合数量和names集合数量一致,说明不是新添加Shape对象
    '可能是用户选择发生变化了触发了CMDBars_OnUpdate事件
    If Not NowShape Is Nothing Then
        If NowShape.name <> name Then
            If Application.ActiveSheet.Shapes.Count = Names.Count Then
                RaiseEvent ShapeSelectChange(NowShape)
            End If
        Else '否则,可能是改变Shape对象的位置或尺寸触发了CMDBars_OnUpdate事件
              '把NoeShape对象的四个属性和四个变量比较,并触发相应的事件
            If name <> "" Then
                If NowShape.Top <> Top Or Left <> Left Then
                    RaiseEvent ShapeMove(NowShape)
                End If
                If NowShape.Width <> Width Or NowShape.Height <> Height Then
                    RaiseEvent ShapeResize(NowShape)
                End If
            End If
        End If
    End If
End Sub
Private Sub GetShapes()
    Dim shp As Shape
    Set Names = New Collection
    With Application.ActiveSheet
        If .Shapes.Count > 0 Then
            For i = 1 To .Shapes.Count
              Names.Add (.Shapes(i).name)
            Next
        End If
    End With
End Sub
Private Sub ShapesEvent()
    Dim shp As Excel.Shape
    With Application.ActiveSheet
    '比较当前Sheets集合数量和Names集合数量,如果不一致,
    '说明可能是添加、删除Shapes对象触发了CMDBars_OnUpdate事件
        If .Shapes.Count > Names.Count Then
            RaiseEvent ShapesAdd(NowShape)
        ElseIf .Shapes.Count < Names.Count Then
            For i = 1 To Names.Count
                On Error Resume Next
                '把删除的对象赋值给shp变量将产生错误
                Set shp = .Shapes(Names.Item(i))
                If Err.Number = -2147024809 Then
                    RaiseEvent ShapesDelete(Names.Item(i))
                    Exit Sub
                End If
            Next
        End If
    End With
End Sub

ThisWorkbook模块代码:
Private WithEvents MyShape As EventShape
'在对象列表框里选择“SelectShape”,在过程列表框里依次单击各个选项,
'添加以下5个事件过程,每个事件过程里添加你自己的代码,
Private Sub MyShape_ShapeMove(ByVal shp As Shape)
    '添加你的代码
    MsgBox "移动图形“" & shp.name & "”"
End Sub
Private Sub MyShape_ShapeSelectChange(ByVal shp As Shape)
    MsgBox "选中图形“" & shp.name & "”"
End Sub
Private Sub MyShape_ShapeResize(ByVal shp As Shape)
    MsgBox "图形“" & shp.name & "”的尺寸改变"
End Sub
Private Sub MyShape_ShapesAdd(ByVal shp As Shape)
    MsgBox "增加图形“" & shp.name & "”"
End Sub
Private Sub MyShape_ShapesDelete(ByVal name As String)
    MsgBox "删除图形“" & name & "”"
End Sub
Private Sub Workbook_Open()
    Set MyShape = New EventShape
End Sub

Shape事件.rar

14.72 KB, 下载次数: 225

评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-10-22 16:30 | 显示全部楼层
这个没意思?OnUpdata是个好东西啊!

点评

OnUpdate 发表于 2014-10-31 13:25

TA的精华主题

TA的得分主题

发表于 2014-10-31 12:49 | 显示全部楼层
这么有料的东东居然没人顶啊。收了

老师应该换个比较噱头标题,如:

谁动了我的Excel?------用OnUpload事件实时监控Excel



Excel克格勃------ComandBar的OnUpload事件

(捂嘴笑)

点评

别犹豫了,发贴吧。  发表于 2014-12-12 09:23

TA的精华主题

TA的得分主题

发表于 2014-10-31 13:40 | 显示全部楼层
Application 级的,同Session跨文件响应...

TA的精华主题

TA的得分主题

发表于 2014-12-12 09:16 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2016-6-17 03:07 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
好东西,支持,并提问:
能否为一些Shape添加MouseMove事件呢?

TA的精华主题

TA的得分主题

发表于 2016-8-18 20:51 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2018-1-8 22:26 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
这个,厉害了!!!

TA的精华主题

TA的得分主题

发表于 2018-1-15 14:00 | 显示全部楼层
谢谢分享 纠结了几天的问题,看到这篇文章,终于解决了,谢谢
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-12-25 15:44 , Processed in 0.043389 second(s), 12 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表