When I started tkinter in another thread, I had a hard time terminating the program normally, so I will share the information.
tkinter loops drawing and event processing by calling mainloop ()
.
You can terminate mainloop ()
by calling destroy ()
on tkinter.
After that, when the thread ends, tkinter is also destroyed.
However, if you called destroy ()
from another thread, or if the tkinter widget (GUI part) was still assigned to the instance variable, the program could not be terminated normally.
I will explain with a sample program.
import time
import threading
import tkinter as tk
class GUI:
def start(self):
self.running = True
self.window = tk.Tk()
self.window.title("Sample")
self.window.geometry('320x240')
self.value = tk.StringVar()
entry = tk.Entry(textvariable=self.value)
entry.pack()
self.window.after(1000, self._check_to_quit)
self.window.mainloop()
# need to delete variables that reference tkinter objects in the thread
del self.value
del self.window
def _check_to_quit(self):
if self.running:
self.window.after(1000, self._check_to_quit)
else:
self.window.destroy()
def quit(self):
self.running = False
def main():
gui = GUI()
thread = threading.Thread(target=gui.start)
thread.start()
time.sleep(2)
for i in 1, 2, 3, 'Dar!!':
gui.value.set(i)
time.sleep(1)
gui.quit()
thread.join()
if __name__ == '__main__':
main()
main ()
creates a gui and a subthread, and the subthread starts gui.start ()
.
When terminating the main ()
process, call gui.quit ()
to set the end flag so that the subthread checks every 1 second and the subthread itself calls destroy ()
. I am doing it.
Calling gui.window.destroy ()
directly instead of this gui.quit ()
caused an infinite loop.
I couldn't even hear CTRL + C
, and I had no choice but to force termination (core dump) withCTRL + \
.
In the subthread, after exiting mainloop ()
, the instance variable is del
.
If this del
processing is not performed, the program may terminate abnormally (core dump) or continue to output error messages endlessly.
Experiment with what happens by doing gui.window.destroy ()
directly from main ()
or commenting out the del processing of instance variables.
Be careful when using tkinter and threads together.