Multiple Timers - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: General Coding Help (https://python-forum.io/forum-8.html) +--- Thread: Multiple Timers (/thread-28125.html) |
Multiple Timers - SenselessScott - Jul-06-2020 Hello, I am currently in the design phase of a app that will be used to time the start, stop and elapsed time of certain events as they are triggered by a user clicking on a button. I want to have several timers (counting durations in hh:mm format) displaying their values each minute. Each of the timers will start, pause and reset based on events triggered by the user clicking on certain GUI buttons. Coming from a vb.net event driven world I had envisioned each timer being an object with methods of aTimer.Start, aTimer.Stop, aTimer.Reset and these objects would be on a form and accumulating time and updating the display constantly. Can someone give me some pointers on how I would approach this using Python? Thank you, Scott RE: Multiple Timers - rexrf - Jul-06-2020 assuming you want these timers to be non blocking? as in running one timer wont stop the program from continuing untill it has completed, and will instead happily run in the background. if this is the case you're going to have make a multithreaded program...which can be painful to say the least in python. RE: Multiple Timers - deanhystad - Jul-06-2020 I think all GUI toolkits have the concept of a timer. In tk you us "after". In Qt you use QTimer. You could use multiple threads or processes, but if this is a GUI app, use what the GUI provides. I would have only one timer and have it process a list of event_timer. An event timer is essentially a function to execute and a time to execute. The can run periodically, checking each event timer and executing the function when the event time is reached. Another choice is to set the timer to execute when the next event is scheduled. The logic is more complicated (you need to find the next event each time an event is added or executed and use that to set the timer wait), but it may result in better precision and less overhead. You may want two types of event timers, periodic and one shot. A periodic event executes after some delay and continues to do so until stopped. A one shot executes after some delay and removes itself from the event timer list. Another possibility is to make everything a one shot and implement a periodic event by having the callback function add a new event timer. This is an event timer I wrote for an application that uses PySide2 (Qt GUI). """Event is a scheduled function call Events are added to a list that is processed during processor free time. The start time is compared to the current time, and the event is run if the elapsed time is greater than the event delay. Running an event calls the event callback with the event arguments. These are set at creation or by calling the "connect" or "execute" methods. The event does not run again unless the "resume method is called "execute" is a one-time event that is removed from the event list after it is run. Use execute to do a delayed function call. Use "start" for events that run periodically. """ import time class Event: """Delayed function call""" events = [] timer = None @classmethod def add_event(cls, event): """Add event to cycle""" if not event in cls.events: cls.events.append(event) @classmethod def remove_event(cls, event): """Remove event from cycle""" cls.events.remove(event) @classmethod def timer_tic(cls): """Run periodically to schedule and fire events""" current_time = time.time() [event.tic(current_time) for event in cls.events] def __init__(self): """Initialize Event.""" self.delay = 0.0 self.callback = None self.args = () self.kwargs = {} self.time = time.time() self.oneshot = False self.active = False self._resume = False def __repr__(self): """Return string representation of event""" return f'(Event {self.callback}) delay {self.delay}, active {self.active}' def tic(self, current_time): """Event countdown""" if not self._resume: self.time = current_time elif current_time - self.time >= self.delay: self._resume = False if self.callback is not None: self.callback(*self.args, **self.kwargs) if self.oneshot: self.stop() def connect(self, callback, *args, **kwargs): """Function to execute when event fires""" self.callback = callback self.args = args self.kwargs = kwargs return self def start(self): """Add event to the cycle""" if not self.active: self.oneshot = False self.active = True Event.add_event(self) self.resume() return self def stop(self): """Remove event from the cycle""" if self.active: self.active = False self.remove_event(self) return self def execute(self, callback, *args, **kwargs): """Use event as a delayed function call. Runs once and is removed from event loop. Option args and kwargs must be list or tuple """ self.callback = callback self.args = args self.kwargs = kwargs self.oneshot = True self.active = True self.resume() Event.add_event(self) def resume(self): """Run event again""" self.time = time.time() self._resume = True return self def setdelay(self, sec): """Set delay between events""" self.delay = sec return self def dump(self): """Print list of events""" for event in self.events: print(event)This is the code in the main program that creates the Event timer. event_timer = QtCore.QTimer(None) event_timer.timeout.connect(Event.timer_tic) event_timer.start(1) RE: Multiple Timers - Yoriz - Jul-06-2020 The Gui would be responsible for calling the method get_duration every update interval.import datetime import time class Timer: def __init__(self): self.timedelta = datetime.timedelta() self.running = False def start(self): self.start_time = datetime.datetime.now() self.running = True def stop(self): if not self.running: return self.timedelta += datetime.datetime.now() - self.start_time self.running = False def reset(self): self.timedelta = datetime.timedelta() self.running = False def get_duration(self): duration = self.timedelta if self.running: duration += datetime.datetime.now() - self.start_time return duration timer = Timer() timer2 = Timer() timer.start() timer2.start() time.sleep(1) print(f'Timer1: {timer.get_duration()}') print(f'Timer2: {timer2.get_duration()}') time.sleep(1) print(f'Timer1: {timer.get_duration()}') print(f'Timer2: {timer2.get_duration()}') timer2.stop() print('Timer2 stopped') time.sleep(1) print(f'Timer1: {timer.get_duration()}') print(f'Timer2: {timer2.get_duration()}') timer2.start() print('Timer2 started') time.sleep(1) print(f'Timer1: {timer.get_duration()}') print(f'Timer2: {timer2.get_duration()}') time.sleep(1) print(f'Timer1: {timer.get_duration()}') print(f'Timer2: {timer2.get_duration()}') timer.reset() timer.start() print('timer1 reset & restarted') time.sleep(1) print(f'Timer1: {timer.get_duration()}') print(f'Timer2: {timer2.get_duration()}') time.sleep(1) print(f'Timer1: {timer.get_duration()}') print(f'Timer2: {timer2.get_duration()}')
|