VBA Excel: Macro should start after timer expires - excel

I am working with Visual Basic Application on Excel. I have a Macro, which should be executed after a time delay. I want to track the waiting time with a timer meanwhile.
I have created an additional module in which I have the following functions:
Public Sub start_time()
Application.OnTime Now + TimeValue("00:00:01"), "next_moment"
End Sub
Public Sub end_time()
Application.OnTime Now + TimeValue("00:00:01"), "next_moment", , False
End Sub
Public Sub next_moment()
If Worksheets("Messwerte").Range("A1").Value = 0 Then Exit Sub
Worksheets("Messwerte").Range("A1").Value = Worksheets("Messwerte").Range("A1").Value - TimeValue("00:00:01")
start_time
End Sub
I have my timer in the cell Worksheets("Messwerte").Range("A1").Value.
The structure of my code is now the following:
For Loop
Code Block 1
Call start_time #Waiting should be applied here
Code Block 2
End For Loop
My problem is now that the timer starts at start_time, but Code Block 2 is also starting. I want to have my timer and when my timer shows "00:00:00" then Code Block 2 should start.
On the forums I just found solutions to either having a timer or to wait until the code is continued but not both working like I want to.
Does someone has a solution on this?
Thanks

I found a solution, which is not clean, but it does work. Hopefully it helps you.
I created a function, which is a boolean and becomes false, when the timer is on 0.
Public Function Check_Time() As Boolean
If Sheets("Timer_Tabular").Range("Timer_Position").Value = 0 Then
Check_Time = False
Else
Check_Time = True
End If
End Function
The code has the following structure:
#Code before the waiting
Dim Waiting as Boolean
Waiting = True
'Wait until timer is zero
Do While Waiting
If Check_Time() = True Then
'Enables working on excel while doing nothing.
DoEvents
ElseIf Check_Time() = False Then
Waiting = False
Exit Do
End If
Loop
#Code Block, which is executed after waiting time.
So the Macro is catched at this point inside the while loop and the while loop breaks, when the timer is 0. The DoEvents "unfreezes" the excel screen.
Endresult is: The macro code stops running, but the timer goes on. If the timer is 0 the code will be continued.

Related

Application.OnTime doesn't wait

I have some graphs that are updated based on the value in one cell. I am trying to write a script that changes the value in this cell every second and updates the graphs in the process. However, the program does not seem to wait one second to call the procedure and rather runs everything directly. I have tried other methods such as Application.wait which works in regards to waiting but it does not update the graphs. From information I have found on the internet, it seems like Application.OnTime is the best option. Could someone help me figure out why Application.OnTime does not wait one second? Here is my code:
Sub graphOverTime()
Do While Range("N5").Value = "Running"
'changes cell N5 to Not running on condition
Call my_procedure
'Update value in D3 that impacts the graphs
current_month = Range("D3").Value
Range("D3").Value =
Application.WorksheetFunction.EoMonth(current_month, 1)
DoEvents
'Wait one second to rerun procedure
Application.OnTime Now + TimeValue("0:00:01"), "graphOverTime"
Loop
End Sub
Your main problem is Do While looping which causes Application.OnTime to set overlapping scheduled calls of graphOverTime. Following is one way of doing what you wanted to in the first place
Sub graphOverTime()
If Range("N5").Value = "Running" Then
'changes cell N5 to Not running on condition
Call my_procedure
'Update value in D3 that impacts the graphs
Range("D3").Value = Application.WorksheetFunction.EoMonth(Range("D3").Value, 1)
DoEvents
'Wait one second to rerun procedure
Application.OnTime Now + TimeValue("0:00:01"), "graphOverTime", False
End If
End Sub

Calling sub not completing before loop moves to next iteration in VBA

I am writing a piece of VBA code to display a countdown timer. Excel Sheet 1 lists times and descriptions of the events and sheet 2 displays the countdown.
The idea is once the first event has successfully counted down, it checks the date of the second event, and if it is today it proceeds to count down to the second event and so on. The countdown aspect works successfully for the first time and description, but when it finishes counting down to the first event it stops altogether.
There are 3 subs, the first works out if the event is today and how long it needs to count down for. The first calls the second which does the counting down by subtracting a TimeSerial(0,0,1) and the third is a timer. I will admit I borrowed the 2nd and 3rd from a nicely written piece I found online (credit to whoever wrote that, thanks).
I have simplified what I have written below:
For i=1 to 10
If *Conditions to determine if countdown should happen exist*
*calculate time to countdown and sets it to sheets("Countdown").Cells("A13")*
Cells(13, 1) = TotaltimeCountdown
Call Countdowntimer
End if
Next i
Sub Countdowntimer()
Sheets("Countdown").Activate
Dim Counter As Range
Set Counter = ActiveSheet.Range("A13")
If Counter.Value > 0 Then
Counter.Value = Counter.Value - TimeSerial(0, 0, 1)
Call Timer
ElseIf Counter.Value <= 0 Then
Sheets("Countdown").Range("A13:H17").ClearContents
Exit Sub
End If
End Sub
'Sub to trigger the reset of the countdown timer every second
Sub Timer()
Dim gCount As Date
gCount = Now + TimeValue("00:00:01")
Application.OnTime gCount, "Countdowntimer"
End Sub
I put a message box after calling Countdowntimer in the first sub and was able to establish that it displayed the amount of time to count down, then displayed the messagebox and cycled through each value of i. Only THEN did it actually proceed with the countdown.
Any suggestions on how to make the for loop pause completely until the countdown from the called sub is finished?
Any suggestions appreciated
The issue is using Application.OnTime and for a count down timer use a Do loop with DoEvents to count down.
Something like that:
Option Explicit
Public Sub CountDownTimer()
With ThisWorkbook.Worksheets("Countdown")
Dim Duration As Long
Duration = 10 ' needs to be in seconds!
'if your cell has a real datetime then use
Duration = .Range("A13").Value * 24 * 60 * 60
Dim TimerStart As Double
TimerStart = Timer()
Do While Timer <= TimerStart + Duration
.Range("A13").Value = TimeSerial(0, 0, TimerStart + Duration - Timer)
DoEvents
Loop
ThisWorkbook.Worksheets("Countdown").Range("A13:H17").ClearContents
End With
End Sub

Problem with building count down timer in Excel using VBA

I was trying to build a count down timer using VBA, and the result can be dynamically output to an Excel cell. I let procedure abc and def recursively call each other (did not set a stop point just for testing), and it worked. However, later with this exact same code I ran again, it failed, and error message was:
Code execution has been interrupted.
Just can't figure out why, I didn't change anything, how could it work and then fail?
I tried On Error Resume Next and Application.DisplayAlert = False, both don't stop the error message popping up and the interruption of the code execution. And if I step through the procedures, it seems fine...
Also I wish to add a dynamic text like "start in how many seconds" like in the comment in another cell. Can it be realized in this way?
Thank you!
Sub abc()
[a1] = [a1] - 1
' [a2] = "Start in " & [a1] & " seconds."
Call def
End Sub
Sub def()
Application.Wait (Now + TimeValue("0:00:01"))
Call abc
End Sub
Rather than trying to do this recursively, with concerns about the call stack, I would use Application.OnTime.
Sub Button1_Click()
Call MyTimer
End Sub
Sub MyTimer()
[a1] = [a1] - 1
Application.OnTime Now + TimeValue("00:00:01"), "MyTimer"
End Sub
I suppose this is still 'recursive' in a fashion, but the procedure exits each time. Only after 1 second has elapsed does it execute the procedure again.
But, either way, you should include some means of stopping the process. For example,
Sub MyTimer()
[a1] = [a1] - 1
If [a1] > 0 Then
Application.OnTime Now + TimeValue("00:00:01"), "MyTimer"
End If
End Sub
Your entire code is working fine for me (also including the [a2] part). I'm on Windows 7 with Excel 2013.
I suggest you include a stopping condition to abc() like
If [a1] > 0 Then
Call def
End If
Please provide some more information.
Why not create a function btw? Does it work for you?
Function wait(seconds As Long)
Dim originalStatusBar As String, i As Long
originalStatusBar = Application.StatusBar
For i = seconds To 0 Step -1
Application.wait (Now + TimeValue("0:00:01"))
Application.StatusBar = "Start in " & i & " seconds"
Next
Application.StatusBar = originalStatusBar
End Function
Then in your sub you just call it like so:
wait 5 'waits 5 seconds and updates status bar with remaining time
or
wait [a1]-1

Can't get Pause Button to resume time properly - Excel VBA

I am coding a Stopwatch Timer in Excel, and I am trying to add a pause button that will stop the timer, also resume when clicked the 2nd time. I have it almost working, but when it resumes it does not continue the stopwatch at the same time, but rather includes all of the elapsed time. The way I have it working is that when you click the pause button it adds the value of "Paused" to a cell and sets the application to "False". If the button is clicked and the cell already says "Paused" it will empty the cell value and call the StartTimer sub and start the timer again.
Example of problem: If I press the button at 1min and 3secs, wait 3mins and resume the timer, it starts counting again at 4min and 3secs.
Example of goal: If I press the button at 1min and 3secs, wait 3mins and resume the timer, it should start counting again at 1min and 4secs.
Here is my current code that i've been working on:
Dim NextTick As Date, t As Date
Sub StartStopWatch()
t = Time
Call StartTimer
End Sub
Sub StartTimer()
NextTick = Time + TimeValue("00:00:01")
Range("M1").Value = Format(NextTick - t - TimeValue("00:00:01"), "hh:mm:ss")
Application.OnTime NextTick, "StartTimer"
End Sub
Sub StopTimer()
On Error Resume Next
Application.OnTime EarliestTime:=NextTick, Procedure:="StartTimer", Schedule:=False
End Sub
Sub ResetTimer()
Range("M1").ClearContents
Range("N1").ClearContents
Range("L2").ClearContents
End Sub
Sub PauseButton()
If Range("L2").Value = "" Then
Range("L2").Value = "Paused"
Application.OnTime EarliestTime:=NextTick, Procedure:="StartTimer", Schedule:=False
Else
Range("L2").ClearContents
Call StartTimer
End If
End Sub
Your code does not reset the start time when paused. But resetting the start time would lose previous elapsed periods. One approach to this problem is to record the number of elapsed seconds each time the clock stops. Subsequence start/stops are added to the running elapsed counter. There is a reset method so you can begin again from zero.
Private StartTime As Date ' Stores timer start time.
Private StopTime As Date ' Stores timer end time.
Private ElapsedTime As Integer ' Store number of seconds between start and end time.
Private TimerRunning As Boolean ' True when the timer is running.
' Resets ElapsedTime and running status.
Public Sub ResetTimer()
ElapsedTime = 0
If TimerRunning Then TimerRunning = False
End Sub
' Starts the timer.
Public Sub StartTimer()
' Record start time.
StartTime = Time
TimerRunning = True
End Sub
' Stops the timer.
' Displays elapsed seconds.
Public Sub StopTimer()
' Record end time.
StopTime = Time
TimerRunning = False
' Calculate numebr of seconds clock was running for.
' Add total to any previous runs.
ElapsedTime = ElapsedTime + DateDiff("S", StartTime, StopTime)
MsgBox "Clock ran for " & ElapsedTime & " seconds", vbInformation, "Clock Stopped"
End Sub
' Pause the timer.
Public Sub PauseTimer()
' Check current status.
If TimerRunning Then
' Stop the clock, capture the end time
' but do not reset the timer.
StopTimer
Else
' Restart the timer.
StartTimer
End If
End Sub
Users only really need access to the pause and reset functions. You could make the start and stop functions internal private methods.
I've stored the elapsed time in an integer. Date and time variables should be used to record when an event occurred, rather than the duration. Why? Because a time variable supports values from 00:00:00 -> 23:59:59 (times of the day). This leaves no room to record events that lasted longer than a day. You can always format the int when displaying.
I havn't understood how exactly your code works and I tried a couple of things but its not working. Basically what I was trying to to was to take the time from the cell M1 itself the next time it starts and then continue from there itself. Look at this code, maybe it will help.
Dim NextTick As Date, t As Date, continue_time As Date
Sub StartStopWatch()
If Range("L2").Value = "" Then
t = Time
Range("L2").ClearContents
Else
t = TimeValue(Range("M1").Text) - Time
End If
't = Time
Call StartTimer
End Sub
Sub StartTimer()
'If Range("L2").Value = "" Then
' continue_time = Time
'Else
' continue_time = TimeValue(Range("M1").Text)
'End If
NextTick = Time + TimeValue("00:00:01")
Range("M1").Value = Format(NextTick - t - TimeValue("00:00:01"), "hh:mm:ss")
Application.OnTime NextTick, "StartTimer"
End Sub
Sub StopTimer()
On Error Resume Next
Application.OnTime EarliestTime:=NextTick, Procedure:="StartTimer", Schedule:=False
End Sub
Sub ResetTimer()
Range("M1").ClearContents
Range("N1").ClearContents
Range("L2").ClearContents
End Sub
Sub PauseButton()
If Range("L2").Value = "" Then
Range("L2").Value = "Paused"
Application.OnTime EarliestTime:=NextTick, Procedure:="StartTimer", Schedule:=False
Else
Call StartStopWatch
End If
End Sub
I actually just figured it out using a code that counts integers and then changed the formatting to mm:ss.
Solution: http://www.ozgrid.com/forum/showthread.php?t=153966

How to refresh Excel file every second?

I have a list of stock prices pulled from Google finance and placed in different sheets in my Excel. I'm wondering, Can I refresh Excel sheet every SECOND (not minute) according to the Google finance stock price?
This can be done without having a macro constantly running. It relies on the Application.OnTime method which allows an action to be scheduled out in the future. I have used this approach to force Excel to refresh data from external sources.
The code below is based nearly exclusively on the code at this link: http://www.cpearson.com/excel/ontime.aspx
The reference for Application.OnTime is at: https://msdn.microsoft.com/en-us/library/office/ff196165.aspx
Dim RunWhen As Date
Sub StartTimer()
Dim secondsBetween As Integer
secondsBetween = 1
RunWhen = Now + TimeSerial(0, 0, secondsBetween)
Application.OnTime EarliestTime:=RunWhen, Procedure:="CodeToRun", Schedule:=True
End Sub
Sub StopTimer()
On Error Resume Next
Application.OnTime EarliestTime:=RunWhen, Procedure:="CodeToRun", Schedule:=False
End Sub
Sub EntryPoint()
'you can add other code here to determine when to start
StartTimer
End Sub
Sub CodeToRun()
'this is the "action" part
[A1] = WorksheetFunction.RandBetween(0, 100)
'be sure to call the start again if you want it to repeat
StartTimer
End Sub
In this code, the StartTimer and StopTimer calls are used to manage the Timers. The EntryPoint code gets things started and CodeToRun includes the actual code to run. Note that to make it repeat, you call StartTimer within CodeToRun. This allows it to loop. You can stop the loop by calling the StopTimer or simply not calling StartTimer again. This can be done with some logic in CodeToRun.
I am simply putting a random number in A1 so that you can see it update.
Sub RefreshFormulasEverySecond()
Dim dtTargetTime As Date
Debug.Print "Started"
Do While Range("A1").Value <> "STOP"
Application.Calculate
dtTargetTime = Now + TimeValue("0:00:01")
Do While Now < dtTargetTime
DoEvents
Loop
Debug.Print Now
Loop
Debug.Print "Stopped"
End Sub
You could have this macro running in the background. Paste it into a VBA module. You can run it from there or else put a button on the sheet and use that to trigger it. It's written to stop running when the word "STOP" is typed in cell A1 of whatever sheet the user is looking at.
I'm not sure it's the greatest idea to have a macro running continuously in the background, but that was the only way I could think of.

Resources