Ever wanted to have a better Timer as a class, but have been bothered by the fact that you still need to have two files?
SetTimer API requires that you give an address of a callback procedure that the timer then triggers. Working around the issue has been a problem because AddressOf only works for procedures in a regular module.
This shouldn't worry you anymore. This is a single file solution that has it's roots on the famous SelfSub/SelfHook/SelfCallback solution by Paul Caton and LaVolpe. In this class however the code has been modified and simplified to fit the use of a simple timer.
Events
Timer(Seconds)
This event triggers just like the regular Timer event. Unlike the regular Timer control, you also get the value that tells how many seconds has passed since the first call. The seconds value is reseted always when Interval property is changed, but you may change the Enabled property without reseting the starting time.
Properties
Enabled
Returns or sets whether the timer is enabled or not. By default this is True. However the timer does not run if Interval is 0 even if it is enabled. Enabled is automatically swithed to False if for some reason the initialization of the timer fails. The timer is initialized every time Enabled = True and Interval > 0.
Interval
Returns or sets the interval of the timer in milliseconds. Can only be 0 or a positive value. By default the value is 0.
Usage
In the general declarations, add the following:
Dim WithEvents Timer As SelfTimer
This way you add the control with the Timer event to the form or object. When you wish to initialize the timer:
Set Timer = New SelfTimer
Timer.Interval = 1000
This creates the timer and makes it trigger Timer event every one second. Also remember to cleanup once you're done:
Set Timer = Nothing
Because of using WithEvents, you also have a procedure where you can place the code you want to run.
Code:
Private Sub Timer_Timer(ByVal Seconds As Currency)
' your code here
End Sub
A demonstration is included in the attachment. Enjoy!
Here is version 1.1 of SelfTimer, finally had some extra spare time so I could post the update.
This update simplifies the SelfCallback code as well as makes it much more efficient (thanks to Paul Caton's improved solution in his Universal DLL Caller). I also made code more "self commented" by making the machine code portion a user defined type (instead of it being a plain long array that is accessed with pre-defined constants).
Also, changing interval doesn't reset the second counter anymore, that can be done separately with Reset.
thank you for this. i used 7 standard timer controls before, and now i use this class. i don't find any trouble of using it. i can use 7 instances of SelfTimer just like standard timer control..
but i want to know, what is the advantage of using this class instead of standard timer control (beside of long interval, and giving an address of a callback procedure if using SetTimer API) ? my previous app is 200 KB in size, but when using this, it increases to 220 KB in size..
I don't see a problem in destroying, as long as it gets properly destroyed (Set Nothing) there should be no issues.
The biggest advantage is the 1 ms accuracy you can get, VB's own Timer can't do as good of a job with that (especially on older Windows machines that maxed out at 35 ms or so). There is also a feature difference: a Timer will not execute when the application is busy, instead it just drops the event as if it never happened. SelfTimer will execute it after application is no longer busy, meaning if there are 5 events to trigger they are all triggered in a row.
SelfTimer can be customized further into a specialized Timer or a class that has a built-in timer. You can't add a Timer into a class (without creating it into an existing form).
If you need smaller executable size for some reason, you should be using an executable compressor. It is impossible to make custom code without it showing up in final executable size.
That would be interesting, and I'm probably unable to help with the issue. The only thing that comes to my mind which could cause problems is that you'd be constantly changing the Interval on each Timer event, but that is a very wild guess. Do you have the problem when using minimal code possible to see the amount of triggered events / second?
Also, note that DoEvents may do harm (imo it is actually pretty dangerous to use it with API timer, in case you do use it).
Comment regarding post #10. You said that if 5 events were waiting then when code is no longer busy, all 5 events would be triggered. At most only 1 of those 5 should process. This is because the other WM_Timer events are not queued up. Validation seems to prove this. If you noticed between last event before loop started and when loop ended, about 13 events would have occurred, but only 1 was raised.
Code:
Interval was set to 100 ms
SecondsValue: 0.438 when a long loop was started
SecondsValue: 1.703 when long loop exited (queued)
SecondsValue: 1.75 next normal event raised
SecondsValue: 1.86 next normal event raised
SecondsValue: 1.969 etc, etc, etc
Suggestion. Maybe add a StopWatch-like start/stop function that uses QueryPerformanceCounter? This way your class can serve two purposes: timer and high resolution counter.
Insomnia is just a byproduct of, "It can't be done"
For now I don't have a high interest on VB6 based projects; I may do something but I probably won't. SelfTimer in the other hand is a bit of a project that I'd like to rather keep overly simple than boost it with too many features.
I prefer to keep the class itself simple. Here is just one way to do achieve arrays; not the only one.
Code:
' SelfTimerWrap.cls
Option Explicit
Private m_ID As Byte
Private WithEvents m_Timer As SelfTimer
Public Property Get ID() As Byte
ID = m_ID
End Property
Public Property Let ID(ByVal NewValue As Byte)
m_ID = NewValue
End Property
Public Property Get Interval() As Long
Interval = m_Timer.Interval
End Property
Public Property Let Interval(ByVal NewValue As Long)
m_Timer.Interval = NewValue
End Property
Private Sub Class_Initialize()
Set m_Timer = New SelfTimer
m_Timer.Enabled = True
End Sub
Private Sub Class_Terminate()
Set m_Timer = Nothing
End Sub
Private Sub m_Timer_Timer(ByVal Seconds As Currency)
Select Case ID
Case 1
' your code here
Case 2
' your code here
Case 3
' your code here
End Select
End Sub
Dim Timers(1 To 3) As SelfTimerWrap
' because late bounding wastes CPU for nothing
Set Timers(1) = New SelfTimerWrap
Set Timers(2) = New SelfTimerWrap
Set Timers(3) = New SelfTimerWrap
' we use ID so that we know which code we want to run in the event
Timers(1).ID = 1
Timers(2).ID = 2
Timers(3).ID = 3
' this enables the timers (they're automatically Enabled by the class, just set Interval = 0 to disable)
Timers(1).Interval = 100
Timers(2).Interval = 1000
Timers(3).Interval = 10000
I know this thread has been dormant for some time, but I think the SelfTimer may solve my problem!
I've downloaded version 1.1 and included it in my project.
My goal here is to create a class function that "Flashes" a label on a form.
By "Flash" I mean set the background color to white for ~1 second, then back to the original color.
I want to do this several (2-3) times to alert the operator to which label he has selected from a list.
So, in the listbox function, when a label is selected, it calls the class function "Flash", and the selected label "Flashes".
Real simple request!
In my "Flash" function, how do I use the SelfTimer to achieve this toggling of backcolors?