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?
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')