1

I am having a problem where my Tkinter UI becomes completley stuck and non-interactive while a for loop is running. My example code print "Looping" while it is in the loop and there is a "Cancel" button on the UI which is supposed to stop the loop, but since I am unable to click the "Cancel" button the loop can not be stopped. So my question is how can I make my tkinter UI usable while a loop is running. Here is the example code:

from tkinter import*
import time

root = Tk()

i=10
flag = False

def loop():
    flag = True
    for i in range(100):
        if flag == True:
            time.sleep(0.5)
            print("Looping")


def canc():
    flag = False


btn = Button(root, text="Start Loop", command=loop).pack()
cncl = Button(root, text="Cancel", command=canc).pack()

root.mainloop()

I have tried creating a new thread for the loop function but this does not work.

Updated code, the UI is responsive, but nothing happens when cancel is pressed:

from tkinter import*
import threading
import time

root = Tk()

i=10
flag = False



def loop():
    flag = True
    for i in range(10):
        if flag == True:
            time.sleep(0.5)
            print("Looping")


def run():
    threading.Thread(target=loop).start()


def canc():
    flag = False


btn = Button(root, text="Start Loop", command=run).pack()
cncl = Button(root, text="Cancel", command=canc).pack()

root.mainloop()
Mihkel
  • 689
  • 7
  • 34
  • Possible duplicate of [How to easily avoid Tkinter freezing?](https://stackoverflow.com/questions/42422139/how-to-easily-avoid-tkinter-freezing) – Random Davis Apr 09 '19 at 16:20
  • Adding a thread doesn't work how? How did you try it, what was the expected result and what happened instead? – Random Davis Apr 09 '19 at 16:21
  • I messed up the code and yes this worked. Now it seems I need to update "flag" every time the loop runs for it to stop. – Mihkel Apr 09 '19 at 18:05

2 Answers2

2

'flag' isnt a global variable so when it is set to False in canc(), the value of the 'flag' local variable in loop() isnt changed and the loop therefore isnt stopped

also root.update() needs to be used to update the GUI

Remedial actions:

from tkinter import*
import threading
import time

root = Tk()

def loop():

    global flag
    flag = True

    for i in range(10):
        if flag == True:
            root.update()
            time.sleep(0.5)
            print("Looping")

def canc():
    global flag
    flag = False

btn = Button(root, text="Start Loop", command=loop).pack()
cncl = Button(root, text="Cancel", command=canc).pack()

root.mainloop()
  • How can I remedy this issue? I tried putting `global flag` in `canc` but this didn't change anything. – Mihkel Apr 09 '19 at 17:58
  • great, no problem –  Apr 09 '19 at 18:41
  • Ah, actually I found a problem with this code, after pressing cancel you can't start the loop again. If this is an easy fix could you please update the answer? If it takes time don't bother. – Mihkel Apr 09 '19 at 18:43
  • The code now re-starts the loop when the Start loop button is clicked. See the updated code above. –  Apr 09 '19 at 18:48
  • Thank you so much. – Mihkel Apr 09 '19 at 18:49
  • no problem, msg me if you have any future problems with this code –  Apr 09 '19 at 18:55
0

I found a way around that problem:

I started my time-consuming job inside a thread and I checked if my thread is still running in a while loop, and inside that, I did update my Tkinter root.

here is my code:

 def start_axis(input):
    print(input)
    time.sleep(5)

def axis():
    t = threading.Thread(target=start_axis, args=("x"))        
    t.start()

    while t.is_alive():
        try:
            root.update()
        except:
            pass

the args part is important so the thread doesn't call the function immediately

erfan
  • 66
  • 2