Expand/Shrink

gTimer

Definition: include xpGUI.e

gdx id = gTimer(rtn action, integer msecs=40, boolean active=true, object user_data=NULL)
Description: Creates a timer which periodically invokes a handler when the time is up.

action: a procedure to be invoked periodically, see ACTION below.
msecs: an interval in miliseconds, you can change the TIME (etc) attribute later.
active: true or false, you can change the RUN attribute later (and from anywhere).
user_data: anything which might be needed in action, or elsewhere, see USER_DATA.
pwa/p2js: Supported.
Example:
-- simplified version of demo\xpGUI\gTimer.exw
include xpGUI.e
constant title = "Timer"
gdx timer, dlg

procedure action(gdx /*id*/)
    gSetAttribute(dlg,"TITLE","%s:%.1fs",{title,time()})
end procedure

timer = gTimer(action,100,true)
dlg = gDialog(NULL,title,`SIZE=260x80`)
gShow(dlg)
gMainLoop()
gTimer

Note that timers are highly system dependent, and not generally noted for their pin-point accuracy. It is almost inevitable that some timer events will trigger a few milliseconds late, and worse, that effect is often cumulative, at least it is so on Windows. For instance were you to run the above with a 1000ms (1s) interval, you would likely see 14.0, 15.1, 16.1, ... 40.1, 41.2, etc. In some cases you may want to periodically restart the timer with a fractionally shorter interval, to counteract any such "drift", and quite probably restart it again on the very next iteration with the full-length interval. The full demo\xpGUI\gTimer.exw has a bCorrectDrift constant and the code needed for at least one way of doing just that, and demo\rosetta\virtunome.exw another way.

A generally useful example of using a timer to allow any currently active drawing processes to abandon before starting a new one can be found in demo\rosetta\VoronoiDiagram.exw. While relatively simple, it can make a huge difference to responsiveness (and in that particular case, not crashing).

DEV re-test:
In one case (Conway’s game of life) setting a timer before the IupShow() prevented the latter from returning for quite some time, and perhaps not until Escape had been keyed, so from that experience I strongly recommend not creating a timer until after an initial gShow() has returned, and probably after setting any ?RASTER?SIZE to NULL, otherwise it may misbehave - in the program just mentioned two things went wrong: Escape had to be keyed twice to close the window, and the canvas did not resize properly, and both were fixed simply by moving the [Iup/]gTimer() creation down three lines.

Using a timer should keep the CPU usage in the low single digits, as opposed to the 100% of a busy loop (which would not be compatible with JavaScript anyway), which is obviously a good thing and especially so should it prolong the battery life of a portable device.
Attributes:
MSECS The time interval in milliseconds. In Windows the minimum value is 10ms.
The aliases "MSEC" and "TIME" can also be used for this.
RUN Starts and stops the timer. Possible values: "YES"/true or "NO"/false.
Returns the current timer state. If you have multiple threads start the timer in the main thread.
The aliases "RUNNING" and "ACTIVE" can also be used for this.
Handlers:
ACTION procedure action(gdx id)
id: identifier of the timer that activated the event.

Called every time the defined time interval is reached.
To stop the handler being called again simply set RUN to false.