1、深入探讨 Excel Application 对象 OnTime 方法的死穴摘 要因为 Excel集数据库和程序设计于一体,令广大 VBA编程爱好者前赴后继地奔走在 Excel考试系统路上,定时器作为考试系统的基本要求,而 Excel却没有 Timer,使爱好者乱了方寸,幸好Application对象 OnTime方法带来了一线生机,但它又无法感知系统时间被修改的弊端,成了 Excel考试系统的死穴,又让爱好者垂头丧气。 关键词探讨 Excel Application 对象 OnTime 方法 中图分类号:TP311.52 文献标识码:A 文章编号:1009-914X(2016)02-0351
2、-01 Excel 考试系统的重点和难点都是定时器的实现,但定时器作为任何考试系统的基本要求,又无法回避,怎样彻底实现 Excel考试系统的定时器功能呢? 一、实现定时器的基本方法 虽然 Excel VBA没有提供定时器,但可以通过 Application对象的OnTime方法实现简单的定时器功能,OnTime 方法能够安排一个过程在将来的特定时间运行,既可以是具体指定的某个时间,也可以是指定的一段时间之后。 语法如下:Application.OnTime EarliestTime,Procedure,LatestTime,Schedule 在 OnTime方法中递归调用 Procedure过
3、程,就可实现定时器。 二、致命的死穴 尽管 OnTime方法可以具体指定的某个时间和指定的一段时间之后两种方式执行 Procedure,但本质上都是具体指定的某个时间,因此一旦修改系统时间,不管是提前或延后时间,让其错过指定时刻,或让指定时刻延后数小时或更长,导致 OnTime方法失效,从而失去定时器的功能,成为 Excel考试系统的死穴。 三、解决方案 许多编程爱好者都在苦苦探索一旦修改系统时间,立刻让 Excel感知系统时间被修改了,从而调整定时器方案,其中想利用类似 lostfocus和 getfocus事件的 Workbook_Activate() 、Workbook_SheetAct
4、ivate() 、Workbook_WindowActivate()等事件的探索者,均以失败而告终,因为 WindowActivate等事件都是在有两个以上 workbook打开时(也就是多个 excel文件) ,互相之间切换起作用,而不是 workbook和其他程序窗口间切换。同理,WindowDeactivate 也得是在多个 workbook时起作用。 经过多次探索,终于发现 Worksheet_Change()或Workbook_SheetChange()可担当此大任,两个事件都在编辑单元格后触发事件,类似 TextChange事件,因为一般而言,Excel 随时随地都处于编辑状态,所
5、以时时刻刻都会触发 Worksheet_Change()或Workbook_SheetChange()事件,只要在事件中获取系统时间,并比较前后时间的变化,即可判断系统时间是否被修改。尤其是系统时间被修改为以前的时间,更容易感知,因为时间毕竟不能倒流。 四、具体实现方法 首先定义两个全局变量 Public pass As Date,Public nowtime As Date,在 Workbook_Open()事件中获取系统时间,启动定时器过程displaytime() 。 Private Sub Workbook_Open() nowtime = Now() pass = nowtime -
6、 TimeValue(“01:00:00“) 防恶意修改系统时间 displaytime End Sub 而在定时器中递归调用过程 displaytime() 。 Public Sub displaytime() nexttime = Now + TimeValue(“00:00:01“) If Range(“D2“).Value TimeValue(“00:00:00“) Then Application.OnTime nexttime, “ThisWorkbook.displaytime“, , True End If End Sub 在 Worksheet_Change()或 Workb
7、ook_SheetChange()事件中利用DateDiff函数比较 pass和 nowtime两个变量,当 nowtime比 pass还早,说明修改了系统时间,提示并作关闭 Excel处理。 Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range) nowtime = Now() If DateDiff(“s“, pass, nowtime) 0 Then 修改系统时间,按提交处理 Response = MsgBox(“ 恶意修改系统时间 “, 0, “提示“) ActiveWorkbook.Sav
8、e Application.Quit Else pass = nowtime 正常,时间在一分一秒过去 End If End Sub 五、定时器在考试系统中的注意事项 在考试系统中,发现修改系统时间进行异常处理时,一般都要在Workbook_SheetChange()中记录考试状态和退出考试的原因,并存放在 Excel文档中,此时又会触发 Workbook_SheetChange()形成递归调用,而又没有递归的退出机制,导致堆栈空间溢出,Excel 出现 1004号错误,使整个考试系统崩溃,那么又怎样避免Workbook_SheetChange()形成递归调用呢?可在事件处理中使用Application.EnableEvents=False禁止触发事件,而处理完成后Application.EnableEvents=True重新启动触发事件。 至此,Excel 考试系统的重点和难点定时器的实现方法探讨完毕,整个考试系统彻底健壮起来了,真正完成了 Excel考试系统的开发工作。参考文献 1 张志群,EXCEL 单元格自定义数字格式探讨,微型电脑应用,2008,24 2 甘伟明,用 Excel构建计算机等级考试自动改卷评分系统,电脑学习 2010,2