Here is a different solution, with the following advantages:
Does not require manually creating separate threads
Does not use Tk.after
calls. Instead, the original style of code with a continuous loop is preserved. The main advantage of this is that you do not have to manually specify a number of milliseconds that determines how often your code inside the loop runs, it simply gets to run as often as your hardware allows.
Note: I've only tried this with python 3, not with python 2. I suppose the same should work in python 2 too, I just don't know 100% for sure.
For the UI code and start/stopping logic, I'll use mostly the same code as in iCodez' answer. An important difference is that I assume we'll always have a loop running, but decide within that loop what to do based on which buttons have been pressed recently:
from tkinter import *
running = True # Global flag
idx = 0 # loop index
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()
while True:
if idx % 500 == 0:
root.update()
if running:
print("hello")
idx += 1
In this code, we do not call root.mainloop()
to have the tkinter GUI continually updating. Instead, we manually update it every so often (in this case, every 500 loop iterations).
Theoretically, this means we may not instantly stop the loop as soon as we hit the Stop button. For example, if at the exact moment where we hit the Stop button, we're at iteration 501, this code will continue looping until iteration 1000 has been hit. So, the disadvantage of this code is that we have a slighlty less responsive GUI in theory (but it will be unnoticeable if the code within your loop is fast). In return, we get the code inside the loop to run almost as fast as possible (only with sometimes overhead from a GUI update()
call), and have it running inside the main thread.