UPDATE 2: How Do I Stop a Function in a while loop? UPDATE 2: How Do I Stop a Function in a while loop? tkinter tkinter

UPDATE 2: How Do I Stop a Function in a while loop?


To ensure a UI remains responsive to user events (mouse clicks etc) and also to system events (like exposure and repainting) you should never enter a long lived loop in a function and never use sleep. Instead Tkinter provides the after method to allow you to schedule something to be done after some interval. This call adds your call into the event queue and its gets processed in due time by the code called by mainloop. For something that should occur after a delay obviously after(num_millis) is used. If you need to poll the state of a pin, then use a short time and in the handler, set another after call to call your polling function again. Note you can cancel after calls provided you retain the id value that is returned when you call the method.

Don't use time.sleep. No UI events will be processed during the sleep and the UI will be dead. Use after.


Your Flag is a module-level variable.

If you want to modify that in a function (without passing it as an argument), you need to mark it as global in the function.

Observe:

In [1]: flag = 0In [2]: def foo(num):   ...:     flag = num   ...:     In [3]: flagOut[3]: 0In [4]: foo(4)In [5]: flagOut[5]: 0In [6]: foo(12)In [7]: flagOut[7]: 0

Calling foo sets a flag, but this is local to the function! It has no effect on the module-level object.

You have to explicitly say that you want to modify the module-level variable:

In [8]: def bar(num):   ...:     global flag   ...:     flag = num   ...:     In [9]: bar(4)In [10]: flagOut[10]: 4In [11]: bar(7)In [12]: flagOut[12]: 7


Thanks @patthoyts and @RolandSmith for the insight that helped lead me to the answer.

2 things they stated were helpful - Not using time.sleep and making sure I was using a global variable.

With some re-work on the Flag idea, and not sleeping but creating a check function to see how much time has passed. Deleted threading for now as it wasn't dire to the GUI process. Big shout out to Tom Slick with the behind the scenes help as well!

from tkinter import *import tkinter.fontimport RPi.GPIO as GPIOimport timeGPIO SetupGPIO.setwarnings(False)GPIO.setmode(GPIO.BOARD)GPIO.setup(16, GPIO.OUT) # Water PumpGPIO.setup(18, GPIO.IN)  # Tank Float SwitchGPIO.output(16, GPIO.LOW)time_to_run = 60 # time to run the pump in secondstime_running = time.time() - 1#Window Setupwin = Tk()win.title("Pump Test")win.geometry("150x150+0+0")#Label SetupLabel (win, text="Water System", fg="red", bg="black", font="24").grid(row=0, column=0)#Functionsdef off():    WTR.config(text="LOW WATER", bg="red")    GPIO.output(16, GPIO.LOW)def wtr():    global time_running    time_running = time.time() + time_to_run    if GPIO.input(18) and not GPIO.input(16):        pump_on()    elif GPIO.input(16):        pump_off()def pump_on():    WTR.config(text="Water", bg="green")           GPIO.output(16, GPIO.HIGH)# added to turn the pump off manualydef pump_off():    WTR.config(text="Water", bg="grey")           GPIO.output(16, GPIO.LOW)def check_pump():    # if the water level goes low turn the pump off    # and show low water level    if not GPIO.input(18):        off()    # if a set time has passed then shut the pump off it it is running    if time_running <= time.time() and GPIO.input(16):        pump_off()    win.after(100, check_pump) # call this function every 100 miliseconds#ButtonsWTR = Button(win, text="Water", bg="grey", command = wtr, height = 2, width = 8)WTR.grid(row=1, column=0) #Water Pump Controlcheck_pump() # must be called once to start the after functionmainloop()