Excel 停止OnTime事件

Excel 停止OnTime事件,excel,vba,event-handling,Excel,Vba,Event Handling,我遇到过一些帖子,其中解释说“要取消挂起的OnTime事件,您必须提供它计划运行的确切时间” 我应该提供第一次运行事件的时间,还是应该提供下一次触发事件的时间 我试过两种版本的StopTimer。都给我 对象\u应用程序的时间方法失败 我对下面的过程测试进行了更改,现在我使用的是STOPTIMER的第三个版本,但我的代码给出了相同的错误 Sub test() If count = 1 Then runwhen = Now + TimeSerial(0, 0, 5)

我遇到过一些帖子,其中解释说“要取消挂起的OnTime事件,您必须提供它计划运行的确切时间”

我应该提供第一次运行事件的时间,还是应该提供下一次触发事件的时间

我试过两种版本的StopTimer。都给我

对象\u应用程序的时间方法失败

我对下面的过程测试进行了更改,现在我使用的是STOPTIMER的第三个版本,但我的代码给出了相同的错误

Sub test()
    If count = 1 Then
        runwhen = Now + TimeSerial(0, 0, 5)
        firstrunTime = runwhen
    Else
        runwhen = Now + TimeSerial(0, 0, 5)
    End If
    If count <> 5 Then
        Application.OnTime runwhen, "TheSub"
    Else
        Call StopTimer
    End If
End Sub
子测试()
如果计数=1,则
runwhen=Now+TimeSerial(0,0,5)
firstrunTime=runwhen
其他的
runwhen=Now+TimeSerial(0,0,5)
如果结束
如果数到5那么
Application.OnTime运行时,“订阅”
其他的
呼叫停止计时器
如果结束
端接头

您的代码在我的机器上运行良好。在这里,我使用第二个版本的StopTimer子程序,并将所有代码放入标准代码模块中。我认为你的代码中的罪魁祸首是你没有声明全局变量:

Public runwhen As Double
Public Const runwhat As String = "TheSub"
Public firstrunTime As Double
Public count As Integer
位于代码模块的顶部。将它们放在
选项Explicit
的正下方,以使其正常工作

FWIW,我修复了您的StopTimer子例程的第一个版本,以使其正常工作:

Sub StopTimer()
    On Error Resume Next
    Application.OnTime runwhen, "TheSub", , False
End Sub

现在,这两个子例程可以互换使用。

要取消OnTime事件,您需要通知它计划运行的时间

您的第一次尝试是告诉它取消一个不再预定的预定事件-它可能实际上发生在几个小时前

您的第二次尝试是告诉它取消计划的事件,该事件将在您决定取消该事件5秒后发生。你可能会很幸运,在你设定了5秒的时间后,你很快就决定取消它,但你可能不会。(这取决于时钟的准确性,以及计算机执行代码的速度。)

您需要做的是告诉它在设置事件的同时取消该事件,因此您的代码需要说明:

'Third Version of StopTimer
Sub StopTimer()
    Application.OnTime runwhen, "TheSub", , False
End Sub
该版本将在取消中使用与在测试子例程中设置时间相同的时间(
runwhen


更新新代码:

您的代码的原始版本本可以工作(使用StopTimer的版本3),但您的新版本失败,因为您已将其更改为设置
runwhen
,而您不应该这样做

让我们逐步了解新版本代码中发生的情况。假设您在上午6:00:00打开工作簿,并且您的CPU非常慢,因此我们可以为各种事件分配不同的时间

06:00:00.000 - Workbook opens
06:00:00.001 - Subroutine Test is called
06:00:00.002 - Count is 1, so first If statement executes the first section
06:00:00.003 - runwhen is set to 06:00:05.003
06:00:00.004 - firstruntime is set to 06:00:05.003
06:00:00.005 - Count is 1, not 5, so second If statement executes the first section
06:00:00.006 - OnTime is set to run TheSub at 06:00:05.003
06:00:00.007 - Subroutine Test finishes and control returns to TheSub
06:00:00.008 - Count is 1, not 5, so If statement is not executed
06:00:00.009 - Subroutine TheSub finishes and execution of macro stops

06:00:05.003 - OnTime event triggers
06:00:05.004 - Subroutine TheSub is called
06:00:05.005 - MsgBox is displayed
               The user is very slow to press the button this time. (Mainly because I had
               written a lot of the following times, and then realised my Count was out
               by 1, and I didn't want to have to rewrite everything - so I just added
               a very slow response here.)
06:00:12.000 - User presses OK
06:00:12.001 - Count is set to 2
06:00:12.002 - Subroutine Test is called
06:00:12.003 - Count is 2, not 1, so first If statement falls into Else portion
06:00:12.004 - runwhen is set to 06:00:17.004
06:00:12.005 - Count is 2, not 5, so second If statement executes the first section
06:00:12.006 - OnTime is set to run TheSub at 06:00:17.004
06:00:12.007 - Subroutine Test finishes and control returns to TheSub
06:00:12.008 - Count is 2, not 5, so If statement is not executed
06:00:12.009 - Subroutine TheSub finishes and execution of macro stops

06:00:17.004 - OnTime event triggers
06:00:17.005 - Subroutine TheSub is called
06:00:17.006 - MsgBox is displayed
06:00:18.000 - User presses OK
06:00:18.001 - Count is set to 3
06:00:18.002 - Subroutine Test is called
06:00:18.003 - Count is 3, not 1, so first If statement falls into Else portion
06:00:18.004 - runwhen is set to 06:00:23.004
06:00:18.005 - Count is 3, not 5, so second If statement executes the first section
06:00:18.006 - OnTime is set to run TheSub at 06:00:23.004
06:00:18.007 - Subroutine Test finishes and control returns to TheSub
06:00:18.008 - Count is 3, not 5, so If statement is not executed
06:00:18.009 - Subroutine TheSub finishes and execution of macro stops

06:00:23.004 - OnTime event triggers
06:00:23.005 - Subroutine TheSub is called
06:00:23.006 - MsgBox is displayed
06:00:24.000 - User presses OK
06:00:24.001 - Count is set to 4
06:00:24.002 - Subroutine Test is called
06:00:24.003 - Count is 4, not 1, so first If statement falls into Else portion
06:00:24.004 - runwhen is set to 06:00:29.004
06:00:24.005 - Count is 4, not 5, so second If statement executes the first section
06:00:24.006 - OnTime is set to run TheSub at 06:00:29.004
06:00:24.007 - Subroutine Test finishes and control returns to TheSub
06:00:24.008 - Count is 4, not 5, so If statement is not executed
06:00:24.009 - Subroutine TheSub finishes and execution of macro stops

06:00:29.004 - OnTime event triggers
06:00:29.005 - Subroutine TheSub is called
06:00:29.006 - MsgBox is displayed
06:00:30.000 - User presses OK
06:00:30.001 - Count is set to 5
06:00:30.002 - Subroutine Test is called
06:00:30.003 - Count is 5, not 1, so first If statement falls into Else portion
06:00:30.004 - runwhen is set to 06:00:35.004
06:00:30.005 - Count is 5, so second If statement executes falls into the Else portion
06:00:30.006 - Subroutine StopTimer is called
06:00:30.007 - Code attempts to cancel Ontime event scheduled for 06:00:35.004 (the value of runwhen),
               but fails because no such event is scheduled)
发生故障的原因是您更新了
runwhen
(在我的示例中为06:00:30.004)的值,但没有设置OnTime事件。然后,您可以取消该活动,但该活动无法取消

在设置OnTime事件时,应仅设置
runwhen
,然后才能使用该变量取消事件

我建议您将整个代码更改为:

'In your Workbook module
Option Explicit

Private Sub Workbook_Open()
    count = 1
    Call StartTimer
End Sub

'In your main code module
Option Explicit

Public runwhen As Double
Public count As Integer

Sub TheSub()
    MsgBox "Hi!!!!!!"
    count = count + 1
    Call StartTimer
End Sub

Sub StartTimer()
    If count <> 5 Then
        runwhen = Now + TimeSerial(0, 0, 5)
        Application.OnTime runwhen, "TheSub"
    End If
End Sub

我在尝试停止Ontime事件时出错,这对我来说很奇怪,因为我有3个计时器,2个正常工作,第三个计时器有时无法停止。我的观察结果如下:当我试图从已调度/重复的子程序或从初始调度子程序调用的任何子程序调用StopTimer时,出现了错误。只有当我从不同的子程序调用StopTimer时,StopTimer才能正常工作。 在TS示例中,停止计划子“TheSub”的命令从“TheSub”本身的主体运行。 以下是我的例子:

public nextTime1 as Date
public nextTime2 as Date

sub StartTimer()
   call Repeat1 'the first scheduled sub
end sub

sub StopRepeat1
   Application.OnTime nextTime1, "Repeat1", , False
end sub

sub StopRepeat2
   Application.OnTime nextTime2, "Repeat2", , False
end sub

sub Repeat1()
 nextTime1 = Now + TimeSerial(0, 0, 5)
 if condition = true then
   call Repeat2
   call StopRepeat1 '< here gives error because I try to stop this sub from itself
 end if 
 Application.OnTime nextTime1, "Repeat1"  
end sub

sub Repeat2()
  nextTime2 = Now + TimeSerial(0, 0, 1)
  call StopRepeat1 '< also gives error because this sub Repeat2 was called from Repeat1, and thus I also try to stop Repeat1 from itself
  'do something
  Application.OnTime nextTime2, "Repeat2"
end sub
public nextTime1作为日期
下一个公共时间2截止日期
亚StartTimer()
将Repeat1'调用为第一个计划的子节点
端接头
子站1
Application.OnTime nextTime1,“Repeat1”,False
端接头
副站2
Application.OnTime nextTime2,“Repeat2”,False
端接头
次重复1()
nextTime1=现在+时间序列(0,0,5)
如果条件=真,则
呼叫中继器2
call StopRepeat1'<此处给出错误,因为我试图从自身停止此子节点
如果结束
Application.OnTime nextTime1,“Repeat1”
端接头
次级重复2()
nextTime2=现在+时间序列(0,0,1)
call StopRepeat1'<也给出了错误,因为这个子Repeat2是从Repeat1调用的,因此我也尝试从自身停止Repeat1
“做点什么
Application.OnTime nextTime2,“Repeat2”
端接头
当我从另一个子系统调用StopRepeat1和StopRepeat2时——按钮为StopRepeat1和StopRepeat2,或者从userform“close”按钮调用StopRepeat1和StopRepeat2时,我一起或仅从一个子系统停止——它正常停止,没有错误。 因此,我避免了一个错误,但我仍然不知道为什么我不能从自身停止Repeat1(因为它的唯一目的是启动Repeat2,当Repeat2启动时,我不需要Repeat1继续运行)。
也许上面的信息对某些人会有帮助。

在第三版StopTimer中,如果没有错误恢复下一步上的语句
,测试子程序将继续运行。我已经在我的机器上试过了。@Anastasiya Romanova秀 - 如果没有错误处理程序,如果取消OnTime事件的尝试失败,将生成错误消息。错误处理程序只会导致执行继续而不会崩溃。您可能认为需要On错误的原因是,当OP将
runwhen
设置为新的、不同的时间时,会发生崩溃。您的最新答案删除了当运行时对
的重置,因此也可以删除出错时的
。如果我没有弄错的话,OP wants Test子程序必须在
计数=5时结束,但如果没有
出错时继续下一步运行
,它将继续运行。@Anastasiya Romanova秀 - 想一想下一次错误恢复时
会发生什么
。。。如果发生错误,就好像取消语句是nev
Application.OnTime runwhen, "TheSub", , False
public nextTime1 as Date
public nextTime2 as Date

sub StartTimer()
   call Repeat1 'the first scheduled sub
end sub

sub StopRepeat1
   Application.OnTime nextTime1, "Repeat1", , False
end sub

sub StopRepeat2
   Application.OnTime nextTime2, "Repeat2", , False
end sub

sub Repeat1()
 nextTime1 = Now + TimeSerial(0, 0, 5)
 if condition = true then
   call Repeat2
   call StopRepeat1 '< here gives error because I try to stop this sub from itself
 end if 
 Application.OnTime nextTime1, "Repeat1"  
end sub

sub Repeat2()
  nextTime2 = Now + TimeSerial(0, 0, 1)
  call StopRepeat1 '< also gives error because this sub Repeat2 was called from Repeat1, and thus I also try to stop Repeat1 from itself
  'do something
  Application.OnTime nextTime2, "Repeat2"
end sub