Jonathan Davies Jonathan Davies - 4 months ago 67
Python Question

How do you create a Tkinter GUI stop button to break an infinite loop?

So I have a Tkinter GUI with two simple options, a start and stop button. I have defined the GUI layout:

from Tkinter import *

def scanning():
while True:
print "hello"

root = Tk()
root.title("Title")
root.geometry("500x500")

app = Frame(root)
app.grid()


Here the Start button runs the infinite loop scanning, and the Stop button should break on press:

start = Button(app, text="Start Scan",command=scanning)
stop = Button(app, text="Stop",command="break")

start.grid()
stop.grid()


However, when I hit the Start button, it is always pushed down (assuming because of the infinite loop). But, I cannot click on the Stop button to break out of the while loop.

Answer

You cannot start a while True: loop in the same thread that the Tkinter event loop is operating in. Doing so will block Tkinter's loop and cause the program to freeze.

For a simple solution, you could use Tk.after to run a process in the background every second or so. Below is a script to demonstrate:

from Tkinter import *

running = True  # Global flag

def scanning():
    if running:  # Only do this if the Stop button has not been clicked
        print "hello"

    # After 1 second, call scanning again (create a recursive loop)
    root.after(1000, scanning)

def start():
    """Enable scanning by setting the global flag to True."""
    global running
    running = True

def stop():
    """Stop scanning by setting the global flag to False."""
    global running
    running = False

root = Tk()
root.title("Title")
root.geometry("500x500")

app = Frame(root)
app.grid()

start = Button(app, text="Start Scan", command=start)
stop = Button(app, text="Stop", command=stop)

start.grid()
stop.grid()

root.after(1000, scanning)  # After 1 second, call scanning
root.mainloop()

Of course, you may want to refactor this code into a class and have running be an attribute of it. Also, if your program becomes anything complex, it would be beneficial to look into Python's threading module so that your scanning function can be executed in a separate thread.

Comments