Threads and tkinter python 3

匿名 (未验证) 提交于 2019-12-03 01:18:02

问题:

I've heard that threads in Python are not easy to handle and they become more tangled with tkinter.

I have the following problem. I have two classes, one for the GUI and another for an infinite process. First, I start the GUI class and then the infinite process' class. I want that when you close the GUI, it also finishes the infinite process and the program ends.

A simplified version of the code is the following:

import time, threading from tkinter import * from tkinter import messagebox  finish = False  class tkinterGUI(threading.Thread):     def __init__(self):         threading.Thread.__init__(self)      def run(self):           global finish         #Main Window         self.mainWindow = Tk()         self.mainWindow.geometry("200x200")         self.mainWindow.title("My GUI Title")         #Label         lbCommand = Label(self.mainWindow, text="Hello world", font=("Courier New", 16)).place(x=20, y=20)         #Start         self.mainWindow.mainloop()         #When the GUI is closed we set finish to "True"         finish = True  class InfiniteProcess(threading.Thread):     def __init__(self):         threading.Thread.__init__(self)      def run(self):         global finish         while not finish:             print("Infinite Loop")             time.sleep(3)  GUI = tkinterGUI() GUI.start() Process = InfiniteProcess() Process.start()

When I click in the close button (in the upper right corner) the following error appears in the console:

Tcl_AsyncDelete: async handler deleted by the wrong thread

回答1:

All Tcl commands need to originate from the same thread. Due to tkinter's dependence on Tcl, it's generally necessary to make all tkinter gui statements originate from the same thread. The problem occurs because mainWindow is instantiated in the tkinterGui thread, but -- because mainWindow is an attribute of tkinterGui -- is not destroyed until tkinterGui is destroyed in the main thread.

The problem can be avoided by not making mainWindow an attribute of tkinterGui -- i.e. changing self.mainWindow to mainWindow. This allows mainWindow to be destroyed when the run method ends in the tkinterGui thread. However, often you can avoid threads entirely by using mainWindow.after calls instead:

import time, threading from tkinter import * from tkinter import messagebox  def infinite_process():     print("Infinite Loop")     mainWindow.after(3000, infinite_process)   mainWindow = Tk() mainWindow.geometry("200x200") mainWindow.title("My GUI Title") lbCommand = Label(mainWindow, text="Hello world", font=("Courier New", 16)).place(x=20, y=20) mainWindow.after(3000, infinite_process) mainWindow.mainloop()

If you want to define the GUI inside a class, you can still do so:

import time, threading from tkinter import * from tkinter import messagebox  class App(object):     def __init__(self, master):         master.geometry("200x200")         master.title("My GUI Title")         lbCommand = Label(master, text="Hello world",                            font=("Courier New", 16)).place(x=20, y=20)  def tkinterGui():       global finish     mainWindow = Tk()     app = App(mainWindow)     mainWindow.mainloop()     #When the GUI is closed we set finish to "True"     finish = True  def InfiniteProcess():     while not finish:         print("Infinite Loop")         time.sleep(3)  finish =         
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!