Stopping the OnTime event

南笙酒味 提交于 2019-12-11 05:11:35

问题


After searching through lot of post, I still can't get my head around it. Please tell me how to stop Application.Ontime event. I have come across posts which explaining To cancel a pending OnTime event, you must provide the exact time that it is scheduled to run

My question is should I supply the time at which the event was run the very first time or should I supply the time at which the event will be triggered next?

I have tried both version of StopTimer in the below codes both of them gives me "Method OnTime of object _Application failed

Option Explicit

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



Public runwhen As Double
Public Const runwhat As String = "TheSub"
Public firstrunTime As Double
Public count As Integer




Sub test()
    If count = 1 Then
        runwhen = Now + TimeSerial(0, 0, 5)
        firstrunTime = runwhen
    Else
        runwhen = Now + TimeSerial(0, 0, 5)
    End If

    Application.OnTime runwhen, "TheSub"
End Sub

Sub TheSub()
    MsgBox "Hi!!!!!!"
    count = count + 1
    Call test
    If count = 5 Then
        StopTimer
    End If
End Sub

'First Version of StopTimer
Sub StopTimer()
    Application.OnTime firstrunTime, "TheSub", , False

End Sub

'Second Version of StopTimer
Sub StopTimer()
    runwhen=now+TimeSerial(0,0,5)
    Application.OnTime runwhen, "TheSub", , False
End Sub

Please fill in what is that I am missing

i have made changes to procedure TEST below and now I am using third version of STOPTIMER but still my code gives me same error

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:


To cancel the OnTime event, you need to advise the time at which it is scheduled to run.

Your first attempt was telling it to cancel a scheduled event that is no longer scheduled - it may have actually occurred several hours ago.

Your second attempt is telling it to cancel a scheduled event that is due to occur 5 seconds after you decided that you wanted to cancel the event. You might be lucky and have managed to decide to cancel it so soon after you set it that 5 seconds is the right time, but you probably won't be. (It depends on how accurate the clock is, and how fast your computer is executing the code.)

What you need to do is tell it to cancel the event with the same time you set it for, so your code needs to say:

'Third Version of StopTimer
Sub StopTimer()
    Application.OnTime runwhen, "TheSub", , False
End Sub

That version will use the same time (runwhen) in the cancellation as was used when you set the time in the Test subroutine.


Update re new code:

The original version of your code would have worked (with version 3 of StopTimer), but your new version fails because you have changed it to set runwhen when you shouldn't.

Let's step through what is happening in the new version of the code. Assume that you open your workbook at 6:00:00 AM, and that your CPU is very slow so that we can assign various times to various events.

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)

The failure occurs because you update the value of runwhen (at 06:00:30.004 in my example), but then don't set the OnTime event. You then go to cancel the event but it isn't there to cancel.

You should set runwhen only when you are setting the OnTime event, and then you will be able to use that variable to cancel the event.

I recommend you change your entire code to be:

'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

If set out that way, you don't need a StopTimer subroutine, because you only start the timer the number of times you want it to run.

However, you are probably trying to design a system where the user will decide when to stop the timer, perhaps by some button click. If so, you would simply need to include in the button's code the following statement to stop the timer:

Application.OnTime runwhen, "TheSub", , False



回答2:


Your code works fine on my machine. Here I use the second version of StopTimer sub-routine and put all of your codes in the standard code module. I think the culprit in your code is you don't declare the global variables:

Public runwhen As Double
Public Const runwhat As String = "TheSub"
Public firstrunTime As Double
Public count As Integer

on the top of your code module. Put them right below Option Explicitin order to make them work properly.

FWIW, I fix your first version of StopTimer sub-routine to make it work properly:

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

Now both of those sub-routines can be used interchangeably.



来源:https://stackoverflow.com/questions/39057696/stopping-the-ontime-event

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!