Reputation: 84
import pyautogui
import time
import PySimpleGUI as sg
def main_app():
try:
layout = [[sg.Text('Enter the number of clicks to perform: '), sg.InputText()],
[sg.Text('Enter the interval between messages (in seconds): '), sg.InputText()],
[sg.Button('Start'), sg.Button('Stop')]]
window = sg.Window('Automatic Clicker', layout)
while True:
event, values = window.read()
if event == 'Start':
num_clicks = int(values[0])
type_interval = float(values[1])
time.sleep(5)
for i in range(num_clicks):
pyautogui.click()
time.sleep(10)
pyautogui.typewrite("Hello, wORLD how are you", interval=5)
pyautogui.press('enter')
time.sleep(type_interval)
time.sleep(5)
if event == 'Stop' or event == sg.WINDOW_CLOSED:
break
except Exception as e:
print(f"An error occurred: {str(e)}")
finally:
window.close()
if __name__ == "__main__":
main_app()
I'm trying to use pysimplegui for creating GUI application,This application is very simple it has 2 buttons start, stop and two input fields where first field takes input to how may times "HELLO World How are you" should be printed. Second input defines delays between printing letters, So when start is given it starts to print the given sentence , but while pressing stop it doesn't stops. instead i have to kill the application from the terminal , how do i make the application stop by pressing stop button
Upvotes: 0
Views: 117
Reputation: 5754
A thread, as Jason's answer shows quite well, is usually the best way to handle these kinds of long operations. I decided to try a slightly different approach. Because so much of your time is simply sleeping, I thought maybe you could get away with using timers to control the flow.
The problem you're running into is that during the time you're sleeping, everything's stopped. The GUI, responding to your input, etc.... it's all stopped.
Using the PySimpleGUI Timer API you can run the timer in the background and continue to perform actions in your GUI.
The implementation is overkill in the use of write_event_value
. This is so that the code could be moved into a thread and then the thread would communicate with the GUI using the same write_event_value
call.
The Timer API calls are not yet released on PyPI, so you'll have to get the latest PySimpleGUI from GitHub. This code will be released to PyPI very soon (by the end of the month or sooner).
#!/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.
"""
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]
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 event == sg.TIMER_KEY and state == State.delay_3_sec: # be sure the if with the timer check AND state is above if with only state
window.write_event_value(NEXT_STATE, State.close_win)
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 event == sg.TIMER_KEY and state == State.delay_2_sec:
window.write_event_value(NEXT_STATE, State.enable_send)
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()
Upvotes: 0
Reputation: 13057
Your script will be blocked by the for
loop with the time.sleep
call, also the GUI not responding, using the sub-thread for your job.
Example Code
import time
import datetime
import threading
import PySimpleGUI as sg
def job(window):
global running
while running:
window.write_event_value('Event', datetime.datetime.now().strftime("%H:%M:%S"))
time.sleep(0.1)
layout = [[sg.Button('Start'), sg.Button('Stop')]]
window = sg.Window('Threading', layout)
running, old = False, None
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
running = False
time.sleep(0.5)
break
elif event == 'Start' and not running:
running = True
window['Start'].update(disabled=True)
threading.Thread(target=job, args=(window, ), daemon=True).start()
elif event == 'Stop':
running = False
window['Start'].update(disabled=False)
elif event == 'Event':
now = values[event]
if now != old:
print(now)
old = now
window.close()
Upvotes: 0