yg213
yg213

Reputation: 25

threading.timer does not get closed

My code is similar to below:

from tkinter import *
from threading import Timer

root = Tk()
###
def print_data():
    Timer(1.0, lambda: print_data()).start()
    data.set('sdsds')
###
data = StringVar()
data_label = Label(root, bg = '#FFF', textvariable = data)
data_label.pack()

timer = Timer(1.0, lambda: print_data());timer.start()
root.mainloop()

This raises RuntimeError: main thread is not in main loop.

What I tried:

root.protocol("WM_DELETE_WINDOW", lambda: timer.cancel())          (close button will not work)

What is wrong?

Upvotes: 1

Views: 335

Answers (1)

martineau
martineau

Reputation: 123541

tkinter doesn't support multithreading in the sense that only one thread in a multithreaded application can use it. Your timer thread breaks that rule and attempts to change the value of the StringVar named data while the mainloop() is running in the main thread.

I don't understand everything your code is trying to accomplish, but the following shows how to do something very similar and avoids the RuntimeError by periodically polling a global flag every 500 ms to see if the print_data() function has ran.

import tkinter as tk  # PEP 8 preferred style.
from threading import Timer

def print_data():
    global printed
    global timer

    printed = True
    timer = Timer(1.0, print_data)
    timer.start()

def check_printed():
    global printed

    if printed:
        data.set('sdsds')
        printed = False
    root.after(500, check_printed)  # Check again in 500 ms.


root = tk.Tk()

data = tk.StringVar()
data_label = tk.Label(root, bg='#FFF', textvariable=data)
data_label.pack()

timer = Timer(1.0, print_data)
timer.start()

printed = False
check_printed()  # Start polling flag.

def shutdown():
    """Orderly app shutdown."""
    if timer.is_alive():
        timer.cancel()
    root.destroy()

root.protocol("WM_DELETE_WINDOW", shutdown)
root.mainloop()

print('fini')

Upvotes: 1

Related Questions