From e050af5c9e19c0a152497fff35d47cac64176cf9 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sat, 3 Feb 2024 10:17:47 -0500 Subject: [PATCH] Added new State Machine Demo Program using Timer API calls --- DemoPrograms/Demo_Timer_API_State_Machine.py | 106 +++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 DemoPrograms/Demo_Timer_API_State_Machine.py diff --git a/DemoPrograms/Demo_Timer_API_State_Machine.py b/DemoPrograms/Demo_Timer_API_State_Machine.py new file mode 100644 index 00000000..b8565bd7 --- /dev/null +++ b/DemoPrograms/Demo_Timer_API_State_Machine.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python +import PySimpleGUI as sg + +""" + Demo - State Machine using timers + + State Machines are very useful when you need to perform a series of operations that you + cannot do all at once due to a time constraint. Particularly problematic are operations + where you would normally use "sleeps" as part of the sequence. + + In this Demo Program, we're going to use the PySimpleGUI Timer API calls to provide our + sleep-like behavior. + + The sequence of operations we're going to run are: + User clicks a "Send" Button to start the sequence: + 1. A "Status Window" is shown that says "Sending" and Disable SEND button + 2. Sleep for 3 seconds + 3. Close the "Status Window" + 4. Sleep for 2 seconds + 5. Enable SEND button and Go to state 1 + + Control of the state machine will be through the PySimpleGUI events. This will enable you to use threads + for any of these states and have the threads communicate the state transitions using the same write_event_value used + in this example. + + Copyright 2024 PySimpleSoft Inc. +""" + + +class State: + stopped = 'stopped' + start = 'start' + delay_3_sec = 'delay 3 seconds' + close_win = 'close win' + delay_2_sec = 'delay 2 seconds' + enable_send = 'enable send' + + +TIMER1 = 3000 +TIMER2 = 2000 +NEXT_STATE = '-NEXT-' + + +def make_send_window(): + layout = [[sg.Text('Send Window')], + [sg.Text('State:'), sg.Text(key='-STATE-')]] + + # Create window a little lower on screen so windows don't overlap + window = sg.Window('Send Window', layout, finalize=True, relative_location=(0, 150)) + return window + + +def main(): + layout = [[sg.Text('State Machine Example', font='_ 14')], + [sg.Text('Click Send to begin sequence')], + [sg.Text('State:'), sg.Text(key='-STATE-')], + [sg.Button('Send', key='-SEND-'), sg.Button('Exit')]] + + window = sg.Window('State Machine Example', layout, font='Any 12') + + window_send = None + state = State.stopped + + while True: + event, values = window.read() + if event == sg.WIN_CLOSED or event == 'Exit': + break + + if event == '-SEND-': + state = State.start + elif event == NEXT_STATE: + state = values[event] + elif event == sg.TIMER_KEY: + if state == State.delay_3_sec: + window.write_event_value(NEXT_STATE, State.close_win) + continue # skip state processing until next_state is received by read + elif state == State.delay_2_sec: + window.write_event_value(NEXT_STATE, State.enable_send) + continue # skip state processing until next_state is received by read + + window['-STATE-'].update(state) + if window_send: + window_send.refresh() + + # ----- STATE MACHINE PROCESSING ----- + if state == State.start: + window['-SEND-'].update(disabled=True) + window_send = make_send_window() + window.write_event_value(NEXT_STATE, State.delay_3_sec) + elif state == State.delay_3_sec: + window.timer_start(TIMER1, repeating=False) + elif state == State.close_win: + window_send.close() + window_send = None + window.write_event_value(NEXT_STATE, State.delay_2_sec) + elif state == State.delay_2_sec: + window.timer_start(TIMER2, repeating=False) + elif state == State.enable_send: + window['-SEND-'].update(disabled=False) + window.write_event_value(NEXT_STATE, State.stopped) + + window.close() + + +if __name__ == '__main__': + main()