Is is possible in python to end a loop in a function from another function? This does not seem to work
Here is my code:
from tkinter import*
root = Tk()
def loop():
global superman
superman=False
while superman==False:
print("It's doing something")
def endloop():
global superman
superman=True
btn_1 = Button(root, text="stop", command=endloop)
btn_1.pack()
btn_2 = Button(root, text="start", command=loop)
btn_2.pack()
The problem here is that your while
loop just keeps running, meaning none of the rest of your code ever gets to run. That includes the Tkinter GUI, which means that your program doesn't respond to any user events, including the button click, so endloop
never gets called.
More generally, you really can't have a function that just runs forever, or even for more than a fraction of a second, inside a GUI program. A single-threaded program can only do one thing at a time; if what it's doing is looping forever, then it's not doing anything else.
So, what can you do?
There are two basic options:
Put the loop on a background thread. This means that any shared data now has to be explicitly synchronized, and it means the loop can't touch any of the GUI widgets—but in your case, that turns out to be pretty simple.
Break up the loop. Have it just do one iteration (or, say, 100 iterations, if they're really quick), and then use after
or after_idle
to ask Tkinter to call a function that does another one iteration (or 100 iterations) and after
s again, and so on, until they're all done.
I'll show you how to do the first one here.
import threading
from tkinter import*
root = Tk()
def real_loop():
while True:
with superman_lock:
if not superman:
return
print("It's doing something")
def loop():
global superman
global superman_lock
superman=False
superman_lock = threading.Lock()
thread = threading.Thread(target=real_loop, daemon=True)
def endloop():
global superman
with superman_lock:
superman=True
btn_1 = Button(root, text="stop", command=endloop)
btn_1.pack()
btn_2 = Button(root, text="start", command=loop)
btn_2.pack()
For the case where the only shared data is a "stop" flag, a Condition
or Event
is often better than a Lock
. The threading
docs explain the differences between the different kinds of sync objects, but not really at an introductory level. The Wikipedia article on monitors might be a better starting point to learn, but if you can find a good tutorial on multithreading (not necessarily Python-specific; Python has basically the same sync objects as the C pthreads library, the C++ Boost library, the Java stdlib, etc.), that would probably be better.
For a much more detailed discussion, see Why your GUI app freezes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With