PySimpleGUI/DemoPrograms/Demo_Timer_Periodic.py

112 lines
3.6 KiB
Python
Raw Normal View History

import PySimpleGUI as sg
import time
"""
Demo Program - Periodic Timer Event
How to use a thread to generate an event every x seconds
One method of getting periodic timer event that's more predictable than using window.read(timeout=x)
The problem with using a timeout with window.read is that if any event happens prior to the timer
expiring, the timer event will not happen. The timeout parameter is not designed to provide a "heartbeat"
type of timer but rather to guarantee you will get an event within that amount of time, be it a
user-caused event or a timeout.
Copyright 2022 PySimpleGUI
"""
timer_running = {}
def timer_status_change(timer_id, start=None, stop=None, delete=None):
"""
Encapsulates/manages the timers dictionary
:param timer_id: ID of timer to change status
:type timer_id: int
:param start: Set to True when timer is started
:type start: bool
:param stop: Set to True when timer is stopped
:type stop: bool
:param delete: Set to True to delete a timer
:type delete bool
"""
global timer_running
if start:
timer_running[timer_id] = True
if stop:
timer_running[timer_id] = False
if delete:
del timer_running[timer_id]
def timer_is_running(timer_id):
"""
:param timer_id: The timer ID to check
:type timer_id: int
:return: True if the timer is running
:rtype: bool
"""
if timer_running[timer_id]:
return True
return False
def periodic_timer_thread(window, interval, timer_id):
"""
Thread that sends messages to the GUI after some interval of time
:param window: Window the events will be sent to
:type window: sg.Window
:param interval: How frequently to send an event
:type interval: float
:param timer_id: A timer identifier
:type timer_id: int
"""
while True:
time.sleep(interval) # sleep until time to send a timer event
window.write_event_value(('-THREAD-', '-TIMER EVENT-'), timer_id)
if not timer_is_running(timer_id): # If timer has been stopped, delete it and return from thread
timer_status_change(timer_id, delete=True)
return
def main():
layout = [[sg.Text('Window with periodic time events')],
[sg.Text(key='-MESSAGE-')],
[sg.Text('Timer Status:'), sg.Text(key='-TIMER STATUS-')],
[sg.Text('Duration:'), sg.In(s=3, key='-DURATION-'), sg.Button('Start')],
[sg.Text('Timer ID:'), sg.In(s=3, key='-STOP ID-'), sg.Button('Stop'),],
[ sg.Button('Dummy'), sg.Button('Exit')], ]
window = sg.Window('Blinking LED Window', layout)
timer_counter = 0
# --------------------- EVENT LOOP ---------------------
while True:
event, values = window.read()
if event in (sg.WIN_CLOSED, 'Exit'):
break
window['-MESSAGE-'].update(f'{event} {values}')
window['-TIMER STATUS-'].update(f'{timer_running}')
if event == 'Start':
if values['-DURATION-']:
timer_status_change(timer_counter, start=True)
window.start_thread(lambda: periodic_timer_thread(window, float(values['-DURATION-']), timer_counter), ('-THREAD-', '-THREAD ENDED-'))
timer_counter += 1
else:
window['-MESSAGE-'].update('Please enter a numeric duration')
elif event == 'Stop':
if values['-STOP ID-']:
timer_status_change(int(values['-STOP ID-']), stop=True)
window.close()
if __name__ == '__main__':
main()