The ResettableTimer class is a timer whose counting loop can be reset arbitrarily. Its duration is configurable. Commands can be specified for both expiration and update. Its update resolution can also be specified. Resettable timer keeps counting until the "run" method is explicitly killed with the "kill" method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | import sys
import threading
import time
from Tkinter import * # for rtTester class
class ResettableTimer(threading.Thread):
"""
The ResettableTimer class is a timer whose counting loop can be reset
arbitrarily. Its duration is configurable. Commands can be specified
for both expiration and update. Its update resolution can also be
specified. Resettable timer keeps counting until the "run" method
is explicitly killed with the "kill" method.
"""
def __init__(self, maxtime, expire, inc=None, update=None):
"""
@param maxtime: time in seconds before expiration after resetting
in seconds
@param expire: function called when timer expires
@param inc: amount by which timer increments before
updating in seconds, default is maxtime/2
@param update: function called when timer updates
"""
self.maxtime = maxtime
self.expire = expire
if inc:
self.inc = inc
else:
self.inc = maxtime/2
if update:
self.update = update
else:
self.update = lambda c : None
self.counter = 0
self.active = True
self.stop = False
threading.Thread.__init__(self)
self.setDaemon(True)
def set_counter(self, t):
"""
Set self.counter to t.
@param t: new counter value
"""
self.counter = t
def deactivate(self):
"""
Set self.active to False.
"""
self.active = False
def kill(self):
"""
Will stop the counting loop before next update.
"""
self.stop = True
def reset(self):
"""
Fully rewinds the timer and makes the timer active, such that
the expire and update commands will be called when appropriate.
"""
self.counter = 0
self.active = True
def run(self):
"""
Run the timer loop.
"""
while True:
self.counter = 0
while self.counter < self.maxtime:
self.counter += self.inc
time.sleep(self.inc)
if self.stop:
return
if self.active:
self.update(self.counter)
if self.active:
self.expire()
self.active = False
class rtTester(Frame):
def __init__(self, parent=None):
self.timer = ResettableTimer(5, self.command, inc=1,
update=self.update)
Frame.__init__(self, parent)
self.pack()
self.make_widgets()
self.timer.start()
def destroy(self, *args, **kwargs):
self.timer.kill()
Frame.destroy(self, *args, **kwargs)
def command(self, e=None):
self.rwbut.config(state = DISABLED)
self.deactbut.config(state=DISABLED)
self.reactbut.config(state = NORMAL)
self.label.config(text='expired', fg='red')
def update(self, c):
self.label.config(text=str(c))
def rewind(self, e=None):
self.timer.reset()
self.label.config(text='0')
def deactivate(self, e=None):
self.rwbut.config(state=DISABLED)
self.reactbut.config(state=NORMAL)
self.deactbut.config(state=DISABLED)
self.label.config(text='deactivated', fg='red')
self.timer.deactivate()
def reactivate(self, e=None):
self.deactbut.config(state=NORMAL)
self.rwbut.config(state=NORMAL)
self.reactbut.config(state=DISABLED)
self.label.config(text='started', fg='black')
self.timer.reset()
def make_widgets(self):
self.rwbut = Button(self, text='rewind', command=self.rewind)
self.rwbut.pack(fill=X)
self.label = Label(self, text='started', fg='black')
self.label.pack(fill=X)
self.deactbut = Button(self, text='deactivate',
command=self.deactivate)
self.deactbut.pack(fill=X)
self.reactbut = Button(self, text='reactivate',
command=self.reactivate,
state=DISABLED)
self.reactbut.pack(fill=X)
def test():
tk = Tk()
rtTester(tk)
tk.mainloop()
if __name__ == "__main__":
test()
|
The key to Resettable Timer's functionality is its 'reset' method, which rewinds and reactivates the timer. The timer can also be arbitrarily advanced, etc., with the "set_counter" method or deactivateed with the "deactivate" method. Thus, the counter can expire, be stopped or be restarted without the necessity to instantiate a new timer, as would be the case with the Timer class.
This efficiency is helpful, for instance, in a GUI environment where the system should otherwise devote resources to handling user generated events. An example of ResettableTimer's usefulness might be to timeout an interface that provides access to sensitive information, such as a password keeper program. The rtTester class demonstrates how to use ResettableTimer.