Jump to content

objStopwatch - Stopwatch Object UDF


Recommended Posts

I stumbled across this recent support thread on using multiple "stopwatches", so I thought I would have a little fun and make a full-featured stopwatch object using AutoItObject_Internal.au3 by @genius257.  It's not super useful, but who doesn't like a full UDF for the simplest of tasks?
This is more of a proof of concept and is not meant to be extremely accurate or reliable, but I'm still open to suggestions if anyone has any ideas for improvement.

The stopwatch has the following methods:

  • start: start (or restart) the timer and reset the accumulated timer value
  • stop: stop/pause the timer
  • lap: return the time since the last time lap was called or since the timer was started
  • reset: stop and reset the timer
  • elapsed: get the time since the last reset or since the timer was started

To use a stopwatch, simply create a new object and start the timer. You can then retrieve the total elapsed time or the current lap time.

#include "ObjStopwatch.au3"

$oStopwatch1 = _ObjStopwatch()
$oStopwatch1.start()
sleep(500)
consolewrite("Lap time: " & $oStopwatch1.lap() & @CRLF)
sleep(500)
consolewrite("Total time: " & $oStopwatch1.elapsed() & @CRLF)

The .elapsed method has 1 optional parameter to set the return formatting.

; Syntax.........: _ObjStopwatch_elapsed ( [$iFormat = 0] )
; Parameters ....: $iFormat = desired format
;                   - 0 = ms with decimal (same as TimerDiff())
;                   - 1 = hh:mm:ss
;                   - 2 = hh:mm:ss:0ms
;                   - 3 = hh:mm:ss.0

Similarly, the .lap method has 2 optional parameters. By passing False as the 2nd parameter, you can poll the current lap time without triggering a new lap.

; Syntax.........: _ObjStopwatch_lap ( [ $iFormat = 0 [, $bNewLap = True ]] )
; Parameters ....: $iFormat = desired format
;                   - 0 = ms with decimal (same as TimerDiff())
;                   - 1 = hh:mm:ss
;                   - 2 = hh:mm:ss:0ms
;                   - 3 = hh:mm:ss.0
;                  $bNewLap = Return the current lap time, and reset lap timer

The real power of this UDF (really all thanks for AutoItObject_Internal) is the ability to create as many Stopwatch objects as you want, which you are then free to start and stop independently.

#include "ObjStopwatch.au3"

$oStopwatch1 = _ObjStopwatch()
$oStopwatch2 = _ObjStopwatch()
$oStopwatch3 = _ObjStopwatch()
$oStopwatch4 = _ObjStopwatch()

$oStopwatch1.start()
$oStopwatch2.start()
Sleep(500)
$oStopwatch1.stop()
Sleep(500)
consolewrite("Stopwatch 1: " & $oStopwatch1.elapsed() & @CRLF)
consolewrite("Stopwatch 2: " & $oStopwatch2.elapsed() & @CRLF)

Lastly, here is a simple GUI example for recording the lap times of 2 different stopwatches.

Spoiler
#include <WindowsConstants.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include "ObjStopwatch.au3"

Opt("GUIOnEventMode", 1)

$AutoItError = ObjEvent("AutoIt.Error", "ErrFunc") ; Install a custom error handler
Func ErrFunc($oError)
    ConsoleWrite("!>COM Error !" & @CRLF & "!>" & @TAB & "Number: " & Hex($oError.Number, 8) & @CRLF & "!>" & @TAB & "Windescription: " & StringRegExpReplace($oError.windescription, "\R$", "") & @CRLF & "!>" & @TAB & "Source: " & $oError.source & @CRLF & "!>" & @TAB & "Description: " & $oError.description & @CRLF & "!>" & @TAB & "Helpfile: " & $oError.helpfile & @CRLF & "!>" & @TAB & "Helpcontext: " & $oError.helpcontext & @CRLF & "!>" & @TAB & "Lastdllerror: " & $oError.lastdllerror & @CRLF & "!>" & @TAB & "Scriptline: " & $oError.scriptline & @CRLF)
EndFunc   ;==>ErrFunc

Global $ListView_1, $ListView_2

;create 2 stopwatch objects
Global $oStopwatch1 = _ObjStopwatch()
Global $oStopwatch2 = _ObjStopwatch()

_main()

Func _main()
    Local $hGUI = GUICreate("MyGUI", 437, 259, 772, 292)
    GUISetOnEvent($GUI_EVENT_CLOSE, "_onExit")
    Local $label1 = GUICtrlCreateLabel("Stopwatch 1:", 5, 4, 81, 18)
    Local $label_time1 = GUICtrlCreateLabel("00:00:00:000", 78, 4, 81, 18)
    Local $button_start1 = GUICtrlCreateButton("Start", 5, 21, 51, 21)
    GUICtrlSetOnEvent(-1, _onStart1)
    Local $button_lap1 = GUICtrlCreateButton("Lap", 56, 21, 51, 21)
    GUICtrlSetOnEvent(-1, _onLap1)
    Local $button_stop1 = GUICtrlCreateButton("Stop", 107, 21, 51, 21)
    GUICtrlSetOnEvent(-1, _onStop1)
    Local $button_reset = GUICtrlCreateButton("Reset", 158, 21, 51, 21)
    GUICtrlSetOnEvent(-1, _onReset1)
    $ListView_1 = GUICtrlCreateListView("Lap Time", 7, 48, 200, 201)
    _GUICtrlListView_SetColumnWidth(-1, 0, 145)

    Local $label2 = GUICtrlCreateLabel("Stopwatch 2:", 230, 4, 81, 18)
    Local $label_time2 = GUICtrlCreateLabel("00:00:00:000", 303, 4, 81, 18)
    Local $button_start2 = GUICtrlCreateButton("Start", 230, 21, 51, 21)
    GUICtrlSetOnEvent(-1, _onStart2)
    Local $button_lap2 = GUICtrlCreateButton("Lap", 281, 21, 51, 21)
    GUICtrlSetOnEvent(-1, _onLap2)
    Local $button_stop2 = GUICtrlCreateButton("Stop", 332, 21, 51, 21)
    GUICtrlSetOnEvent(-1, _onStop2)
    Local $button_reset2 = GUICtrlCreateButton("Reset", 383, 21, 51, 21)
    GUICtrlSetOnEvent(-1, _onReset2)
    $ListView_2 = GUICtrlCreateListView("Lap Time", 232, 48, 200, 201)
    _GUICtrlListView_SetColumnWidth(-1, 0, 145)

    GUISetState(@SW_SHOWNORMAL)

    ;some variables to hold values
    Local $Time1, $Time2, $Lap1, $Lap2
    Local $prevTime1, $prevTime2, $displayTimer = TimerInit()

    While 1
        $Time1 = $oStopwatch1.elapsed(2)
        $Time2 = $oStopwatch2.elapsed(2)

        ;timer to slow down label flicker
        If TimerDiff($displayTimer) > 100 Then
            If $Time1 <> $prevTime1 Then
                GUICtrlSetData($label_time1, $Time1)
                $prevTime1 = $Time1
            EndIf

            If $Time2 <> $prevTime2 Then
                GUICtrlSetData($label_time2, $Time2)
                $prevTime2 = $Time2
            EndIf

            $displayTimer = TimerInit()
        EndIf

        Sleep(10)
    WEnd

EndFunc   ;==>_main

Func _onStart1()
    $oStopwatch1.start()
EndFunc   ;==>_onStart1

Func _onLap1()
    GUICtrlCreateListViewItem($oStopwatch1.lap(2), $ListView_1)
EndFunc   ;==>_onLap1

Func _onStop1()
    $oStopwatch1.stop()
EndFunc   ;==>_onStop1

Func _onReset1()
    $oStopwatch1.reset()
    _GUICtrlListView_DeleteAllItems($ListView_1)
EndFunc   ;==>_onReset1

Func _onStart2()
    $oStopwatch2.start()
EndFunc   ;==>_onStart2

Func _onLap2()
    GUICtrlCreateListViewItem($oStopwatch2.lap(2), $ListView_2)
EndFunc   ;==>_onLap2

Func _onStop2()
    $oStopwatch2.stop()
EndFunc   ;==>_onStop2

Func _onReset2()
    $oStopwatch2.reset()
    _GUICtrlListView_DeleteAllItems($ListView_2)
EndFunc   ;==>_onReset2

Func _onExit()
    GUIDelete()
    Exit
EndFunc   ;==>_onExit

 


Updated 2022-08-29:  ObjStopwatch.au3

  • Fixed time formatting issue.

Prerequisite: AutoItObject_Internal.au3 is required. Download [HERE].

Edited by kurtykurtyboy
update
Link to post
Share on other sites

hey, I thought I'd do the same thing using @genius257's own AutoItObject_Internal
Thanks for saving me the trouble.... :)
Nice work of course, and also an interesting usage example for the AutoItObject_Internal.

 

image.jpeg.9f1a974c98e9f77d824b358729b089b0.jpeg Chimp

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Link to post
Share on other sites

... trying the examples I'm experiencing "crashes" ...
I do further tests ...

 

image.jpeg.9f1a974c98e9f77d824b358729b089b0.jpeg Chimp

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Link to post
Share on other sites

Works fine for me on 3.3.14.5.

Thanks

Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

Link to post
Share on other sites

@Gianni Actually, I saw a few random crashes when testing it but it was so few and far between that I chalked it up to hitting F5 too fast between runs. I ended up putting the COM error handler in the example to try and catch that crash, but I couldn't get it to happen again.

Well I tried getting it to crash again and it took about 20 tries but it finally crashed. It showed the GUI briefly then disappeared and gave the following exit code. I'm not sure how to troubleshoot since it doesn't appear to be a COM error and it's not a normal error that is reported in the console - just a silent crash. For now I'm adding a bunch of log messages to see where it might be crashing.
I'm using v3.3.16.0.

image.png.b40e9bcf0f655517961f585a62e49fbf.png

Link to post
Share on other sites

Hi @kurtykurtyboy.

That error code translates to 0xC0000005 (Access Violation).

It occurs when non accessible data access is attempted.

Mostly it happens when freed memory is accessed and the now possibly random data end up being used as a pointer to a non accessible memory pointer reference.

If it's my code only at fault, it is a tedious, but easy process of finding the faulty code. However i have found that some VERY specific cases can result in AutoIt3 crashing, that seems to be an issue with AutoIt3. see this issue i have in another project of mine for example. Trouble is confirming that is is not my code being the culprit is hard when it comes to memory manipulation and complex scenarios.

Link to post
Share on other sites
  • kurtykurtyboy changed the title to objStopwatch - Stopwatch Object UDF

I still did a small test using the "Simple Gui Example" script present in the spoiler of the first post, and I modified this portion of code

While 1
        ConsoleWrite("Debug 1" & @CRLF)
        $Time1 = $oStopwatch1.elapsed(2)
        ConsoleWrite("Debug 2" & @CRLF)
        $Time2 = $oStopwatch2.elapsed(2)
        ConsoleWrite("Debug 3" & @CRLF)

        ;timer to slow down label flicker
        If TimerDiff($displayTimer) > 100 Then
            If $Time1 <> $prevTime1 Then
                GUICtrlSetData($label_time1, $Time1)
                $prevTime1 = $Time1
            EndIf
            ConsoleWrite("Debug 4" & @CRLF)
            If $Time2 <> $prevTime2 Then
                GUICtrlSetData($label_time2, $Time2)
                $prevTime2 = $Time2
            EndIf

            $displayTimer = TimerInit()
        EndIf

        Sleep(10)
        ConsoleWrite("Debug 5" & @CRLF)
    WEnd

where I added some consolewrite to see where the script crashes and it seems that the line that he does not like is $time2 = $stopwatch2.elaPsed (2)
I tried the script on two different computers (both with Win10 Pro x64) and I receive two different crash type:
This on a computer:

Debug 1
Debug 2
Debug 3
Debug 5
Debug 1
Debug 2
!>17:13:05 AutoIt3.exe ended.rc:-1073741819
+>17:13:05 AutoIt3Wrapper Finished.
>Exit code: 3221225477    Time: 8.258

And this on another computer:

Debug 1
Debug 2
Debug 3
Debug 5
Debug 1
!>17:23:36 AutoIt3.exe ended.rc:255
+>17:23:36 AutoIt3Wrapper Finished.
>Exit code: 255    Time: 12.38

... just for the record ...

 

image.jpeg.9f1a974c98e9f77d824b358729b089b0.jpeg Chimp

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...