Reset a Timer

What’s the best way to determine if a Timer is going to fire, and if not, reset it so that it does fire again, but, also to avoid re-starting it if it’s already going.

The problem I’m running into is that, within a Timer.Action event, Timer.Mode = Timer.ModeSingle.

So this code will sometimes work, sometimes not:

  if mTimer.Mode = Timer.ModeOFF then
      mTimer.Mode = Timer.ModeSingle // cause the timer to fire again
  else
    // the timer is already running, so we Don't want to reset it in this case
  end if

I’m not sure I understand the problem, so let me restate it with made-up numbers to see if I have it right.

You have a Timer whose period is set to 1000 ms. At some point that Timer is started.

With 200 ms left to go, some code needs to make sure the Timer is going to fire, but if it just sets Mode to ModeSingle, it will push the next firing time out to 1000 ms, even though you want to ensure it fires at its scheduled time 200 ms from that point. Is that it?

If so, I’m not sure why if Timer1.Mode <> Timer.ModeSingle doesn’t work consistently. Do you have an idea as to why that might fail?

As an alternative, create the Timer as a property and use AddHandler for its action. When you need to start the Timer, create it and set its Period and Mode. When it’s done, remove the handler and set the property to nil. The logic is, if the Timer exists, it’s running.

Sub MaybeStartTimer()
  if MyTimer is nil then
    MyTimer = new Timer
    AddHandler MyTimer.Action, AddressOf MyTimerAction
    MyTimer.Period = somePeriod
    MyTimer.Mode = Timer.ModeSingle
  end if
End Sub

Sub MyTimerAction (sender As Timer)
    // The code you need it to do

  MyTimer.Mode = Timer.ModeOff
  RemoveHandler MyTimer.Action, AddressOf MyTimerAction
  MyTimer = nil
End Sub

Call MaybeStartTimer freely when needed.

Kem, you have it right. “Fire a timer, but if it’s already set to go, don’t delay it.”

In my testing, I see that inside a Timer.Action event, Timer.Mode = ModeSingle. Your suggestion about forcing ModeOff is a good one, but this seems like it shouldn’t be that hard, so I was wondering if I was doing it wrong.

Why not just check the mode of the timer? Timers can have:

ModeOff
ModeSingle
ModeMultiple

So code would be something like:

If Timer.Mode = Timer.ModeOff Then
    Timer.Mode = Timer.ModeSingle
End If

I’m not entirely sure where the difficulty is arising.

Help me understand…

[quote=216098:@Michael Diehr]What’s the best way to determine if a Timer is going to fire, and if not, reset it so that it does fire again, but, also to avoid re-starting it if it’s already going.

The problem I’m running into is that, within a Timer.Action event, Timer.Mode = Timer.ModeSingle.

So this code will sometimes work, sometimes not:

if mTimer.Mode = Timer.ModeOFF then mTimer.Mode = Timer.ModeSingle // cause the timer to fire again else // the timer is already running, so we Don't want to reset it in this case end if [/quote]

Your code should work just fine as it is. Where do you place it ?

The other thing I don’t understand is why he is worried about the mode of a timer inside the action event of the timer. Inside the action event, the timer has fired. It gets reset when the action event finishes.

This is clearly a bug in Cocoa, which I’ve submitted here: <https://xojo.com/issue/40965>

John asks [quote]The other thing I don’t understand is why he is worried about the mode of a timer inside the action event of the timer. Inside the action event, the timer has fired. It gets reset when the action event finishes[/quote]

The answer is that in a complex app, there are often multiple code pathways : A method “FooBar()” may not be aware of (and, indeed, via good design principles for OOP, should not care) how it was called.

The problem is not generally that this bug is hard to deal with in a toy example, but rather it’s a subtle bug that crops up in real-world use. My code which worked fine on Win32 and Carbon started behaving oddly in Cocoa builds, and it wasn’t until just now that I figured out why…

And… further testing does not show the issue in the latest 2015 R3 beta builds, so perhaps this is an issue that was fixed at some point?

I’m using 2014R2.1 where I clearly see the bug…

[quote=216286:@Michael Diehr]And… further testing does not show the issue in the latest 2015 R3 beta builds, so perhaps this is an issue that was fixed at some point?

I’m using 2014R2.1 where I clearly see the bug…[/quote]

That is why it did not show here. Just move to a more recent version, then. Maybe 2.4 won’t show the issue.

If you absolutely need to use 2.1, you could subclass the timer and set a flag when the timer starts. Maybe using a computed property shadowing mode.

You could also use Xojo.Core.Date.Nanoseconds stored upon start so you can check the time remaining to fire by comparing to Period.

Yeah, I’m not sure where the problem is. It doesn’t appear to be in the most recent version.

I just tried a very simple project. A Window and a Timer. The timer is mode multiple and set to execute every second (Default settings). I have one line in the timer action event:

If me.Mode = Timer.ModeSingle Then Break

The app just happily runs.

Now I just tried changing the timer to a single mode and it still didn’t break. So then I changed the code to:

If me.Mode = Timer.ModeOff Then Break

Now it breaks when the timer fires.

So this appears to be working now.

Here’s what I got:

if mTimer.mode = Timer.modeOFF then mTimer.mode = 1 mTimer.reset //Technically, this is a redundancy as changing the mode *should* reset the timer, but perhaps this addition will help. end if

Make sure that the period property is set in the inspector or through an Open event or the like. You do not want period = nil.

Hopefully this helps…