Welcome!

By registering with us, you'll be able to discuss, share and private message with other members of our community.

SignUp Now!

VB6 SelfTimer class module [2008-06-15]

Merri

VB6, XHTML & CSS hobbyist
Joined
Oct 28, 2002
Messages
6,654
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

[tt]Timer(Seconds)[/tt]
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

[tt]Enabled[/tt]
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.

[tt]Interval[/tt]
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:

[tt]Dim WithEvents Timer As SelfTimer[/tt]

This way you add the control with the Timer event to the form or object. When you wish to initialize the timer:

[tt]Set Timer = New SelfTimer
Timer.Interval = 1000[/tt]

This creates the timer and makes it trigger Timer event every one second. Also remember to cleanup once you're done:

[tt]Set Timer = Nothing[/tt]


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!


IMPORTANT! THERE IS A NEW VERSION IN POST #5!
 
Last edited:

Merri

VB6, XHTML & CSS hobbyist
Joined
Oct 28, 2002
Messages
6,654
VB6 SelfTimer class module [2008-06-23]

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.
 
Last edited:

edhanz

New member
Joined
Aug 12, 2008
Messages
136
Hi Merri,

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..

thank you..
 

edhanz

New member
Joined
Aug 12, 2008
Messages
136
and 1 more thing..
do i have to destroy it in Form_Terminate? currently i destroy it in Form_QueryUnload
 

Merri

VB6, XHTML & CSS hobbyist
Joined
Oct 28, 2002
Messages
6,654
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.
 

Nanni

New member
Joined
Oct 10, 2008
Messages
111
Hi Merri

I'm trying your class, but I have a problem with Timer settings' interval.

Setting Timer.Interval =1000 ,
I get the timer fires every second (1000ms = 1second).

When I set 40ms, the timer do not fires 25 time in 1 second,
but fires about 50 time in 1 second.

Can you help me understand what I'm doing wrong?

Thanks for your time
Nanni
 

Merri

VB6, XHTML & CSS hobbyist
Joined
Oct 28, 2002
Messages
6,654
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).
 

Nanni

New member
Joined
Oct 10, 2008
Messages
111
Hi Merri
Thanks for reply.

In my project I used the timer for counting Video Frames.

Now I have build a new project with only your Timer Class and
I don't have the problem.

I think the problem is with my code. :confused:
I will check it better.

Thanks again
Nanni
 

LaVolpe

VB-aholic & Lovin' It
Joined
Oct 10, 2007
Messages
18,940
Merri, one comment and one suggestion.

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.
 

Merri

VB6, XHTML & CSS hobbyist
Joined
Oct 28, 2002
Messages
6,654
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.
 

VietPubic

New member
Joined
May 1, 2010
Messages
1
Thanks Merri !!
I'm using your code, but now I want declare in a module

Dim WithEvents Timer As SelfTimer

But not work, because i writing a windows service using timer, service not include interface form.

my code
Code:
Call SetTimer(0&, 0&, Frequency, AddressOf TimerProc)

But not work, perhap hwnd para not work because not have window
 

edhanz

New member
Joined
Aug 12, 2008
Messages
136
Hi Merri. Do you stil working on this timer? If yes, maybe you can make it so it can be loaded as an array..
 

Merri

VB6, XHTML & CSS hobbyist
Joined
Oct 28, 2002
Messages
6,654
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


[tt]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[/tt]
 

Ken Whiteman

New member
Joined
Jan 18, 1999
Messages
264
Hi,

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?

Thanks!
 
Top