ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

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

禁用事件操作过程中出现的状况

[复制链接]

TA的精华主题

TA的得分主题

发表于 2012-10-17 14:40 | 显示全部楼层 |阅读模式
最近在看《别怕,Excel VBA其实很简单》。在第132页操作过程中出现过一个问题。

Option Explicit
Private Sub Worksheet_SelectionChange(ByVal target As Range)
    target.Value = target.Address
    Application.EnableEvents = False ‘代码①
    Application.EnableEvents = True ‘代码②
End Sub
此代码的作用是:将选中的单元格地址写入单元格。

代码①和代码②同时存在的时候,事件发生正常。
我想查看代码①和代码②在事件发生时具体的区别。就尝试先Rem 代码②。
发生的情况是事件执行了一次之后不再执行。(因为执行了代码①,所以此现象正常。)
但是,把代码②前的Rem注释标识去掉后,再点击单元格,无任何事件发生。代码不启任何作用了。

我在论坛没有找到发生这一现象的原因,不过找到了解决这个情况的方法。
解决方法:在立即窗口执行代码 Application.EnableEvents = True,然后重新再点击单元格的时候,事件发生正常了。

我希望:
1. 碰到同样问题的读者可以知道解决方案。
2. 知道其中原委的高手帮忙解释一下原因。

非常感谢!

TA的精华主题

TA的得分主题

发表于 2012-10-17 16:01 | 显示全部楼层
首先,得时刻记住两点:
1、通过代码Application.EnableEvents = False禁用事件后,任何操作都不会触发Excel事件。
2、如果禁用了事件,想再次启用事件,得运行代码Application.EnableEvents = False来启用事件。

接下来我们再来看你的问题。
你在程序中保留了Application.EnableEvents = False ‘代码①,即:运行程序后会禁用事件。
但同时,你在程序中注释掉了Application.EnableEvents = True ‘代码②,那运行程序时将不运行这句代码,即:运行程序后禁用了事件却没有重新启用事件。
是的,你的程序禁用事件后却没有重新启用事件。就算是程序运行结束后,这种“禁用”的状态也一直保持着。
所以,你在Excel中做了任何的操作都不会发生事件,因为事件的开关在你上次运行程序后,一直都还关着呢。就算你现在手动去取消注释程序中的Application.EnableEvents = True ‘代码②,但因为不会发生事件,所以这个程序不会被运行,这行启用事件的代码也不会执行,开关继续着着。

但当你在立即窗口中运行Application.EnableEvents = True或通过其他方式运行Application.EnableEvents = True后,就启用事件了。
于是,操作正常了。

不知道我这样的解释是否对你有帮助?

评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-10-17 16:18 | 显示全部楼层
ggsmart 发表于 2012-10-17 16:01
首先,得时刻记住两点:
1、通过代码Application.EnableEvents = False禁用事件后,任何操作都不会触发Exc ...

有一处疑惑始终没有解开。

Application.EnableEvents = False ‘代码①
Application.EnableEvents = True ‘代码②
同时存在的情况下,每次点击单元格事件都会发生。即选中一个单元格,就是在当前单元格显示地址。
是否意味着False和True都被执行了?
为什么一旦注释了True命令,再解除注释就不执行事件了呢?

问题的症结是:如果同时执行代码①和代码②,“禁用”的状态就没有关着呢?
另外,为什么在代码窗口运行Ture没有效果,在立即窗口运行True命令就有效果了呢?

期待你的回复,谢谢。

TA的精华主题

TA的得分主题

发表于 2012-10-17 16:38 | 显示全部楼层
问题一:两条代码同时存在的情况下,是否意味着两条代码都被执行?
答:从你的程序来看,是的,两条代码如果都存在,则两行代码都会执行,并且按先后顺序执行。即:先禁用事件,再启用事件。

问题二:为什么注释了True命令,再次解除注释就不执行事件过程?
答:因为你上一次运行事件过程时禁用了事件,但因为注释了True语句的缘故,所以在上次运行事件过程时只是禁用了事件并没有重新启用事件。
事件的开关一直关着,所有的事件都不会被识别到,该事件过程也不会再执行。在你重新启用事件之前,永远不会被执行。
所以,虽然你取消注释了True语句,但因为这行语句一直没被执行过,并不是说你取消注释了True语句,就启用了事件。取消注释这行语句只是让这行代码变为正常的代码,但但你只是取消注释,并没有执行它,所以开关就一直是关着的,事件过程当然不能执行了。

问题三:如果同时执行False语句和True语句,禁用的状态是关着的吗?
答:事实上,准确点说,你不可能同时执行两行语句。这两行语句放在同一个程序中,当你执行这个程序后,两行代码都会被执行,但它们有被执行的先后顺序,在没有使用任何分支、循环语句的情况下,排在前面的代码总是被先执行,排在后面的代码总是后执行。禁用事件的开关是关着还是开着,就看你在程序中最后执行的是哪条语句。执行False语句,开关关着。执行True语句,开关开着。

问题四:为什么在代码窗口中运行True语句没有效果果,在立即窗口中运行就有效果了?
答:我得说的是代码窗口还是在立即窗口中运行True语句都有效果。也许是你操作失误了。你把True语句写在一个单独的普通Sub过程里试试。如在代码窗口中写入:

  1. Sub ggsmart()
  2.     Application.EnableEvents = True
  3. End Sub
复制代码

然后将光标定位到该程序的中间,按F5键执行它后再看看。

TA的精华主题

TA的得分主题

发表于 2012-10-17 16:38 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
很久没有在论坛回复帖子写这么多的内容了。呵呵。

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-10-17 16:59 | 显示全部楼层
ggsmart 发表于 2012-10-17 16:38
很久没有在论坛回复帖子写这么多的内容了。呵呵。

非常感谢你的回答。虽然我还是没有完全弄明白其中的奥妙。
不过,我个人觉得对于初学者来说,太钻牛角尖不是一件好事。
我相信在看完整本书后,可能会对代码的真正含义有了新的认识。
到时候再回来看你的解释,或许就茅塞顿开了。再次感谢~

TA的精华主题

TA的得分主题

发表于 2012-10-17 17:03 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
牛角尖,钻钻也是好的。

你好好再琢磨一下,随时交流。和大家讨论问题我觉得很高兴。

TA的精华主题

TA的得分主题

发表于 2012-10-18 11:15 | 显示全部楼层
哈哈,刚在另外一个帖子里和一位朋友讨论这个语句呢。
叶枫老师已经在这里给出详细的解释了。

就是当注释掉 Application.EnableEvents = True后,在Application.EnableEvents = False的情况下,
即使取消掉 Application.EnableEvents = True 前面的注释,但是当前状况是事件激活被禁用了。
Selection_Change 事件将无法被激活,那么事件内的代码也没有机会运行,所以没机会执行到
Application.EnableEvents = True 这句代码。
因此需要在立即窗口 执行该句代码 将事件激活状态恢复。

TA的精华主题

TA的得分主题

发表于 2012-10-18 11:23 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
另外针对该例子程序,我想提一点点代码健壮性的问题。作为理解selection_change 事件的例子,这程序非常生动形象,非常好。可是大家操作的时候如果选择了多单元格,就是单元格多于1 个的时候,事件程序会出错。
  1. Private Sub Worksheet_SelectionChange(ByVal Target As Range)
  2.     If Target.Count > 1 Then  '判断是否选择多单元格,如果是就弹出提示窗口
  3.     MsgBox "请选中唯一单元格,而不是一片区域", , "提示"
  4.     Exit Sub  '退出事件过程
  5.     End If
  6.     Target.Value = Target.Address
  7.     Application.EnableEvents = False
  8.     Target.Offset(1, 0).Select
  9.     Application.EnableEvents = True

  10. End Sub
复制代码
我在学习后的一点点理解,请老师指正。

TA的精华主题

TA的得分主题

发表于 2012-10-18 12:07 | 显示全部楼层
hehex 发表于 2012-10-18 11:23
另外针对该例子程序,我想提一点点代码健壮性的问题。作为理解selection_change 事件的例子,这程序非常生动 ...

讲解得非常详细、正确。
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

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

GMT+8, 2024-5-8 08:20 , Processed in 0.050167 second(s), 14 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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