线程和tkinter [英] Threads and tkinter
问题描述
我听说Python中的线程不容易处理,并且与tkinter更加纠结.
I've heard that threads in Python are not easy to handle and they become more tangled with tkinter.
我有以下问题.我有两个类,一个用于GUI,另一个用于无限过程.首先,我启动GUI类,然后启动无限进程类.我希望当您关闭GUI时,它也可以完成无限过程并且程序结束.
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
我不知道为什么会发生或者它意味着什么.
I don't know why it happens or what it means.
推荐答案
所有Tcl命令都必须源自同一线程.由于tkinter
的
依赖于Tcl,通常需要制作所有tkinter
gui语句
源于同一线程.发生问题是因为
mainWindow
是在tkinterGui
线程中实例化的,但是-因为mainWindow
是tkinterGui
的属性,所以-在主线程中将tkinterGui
销毁之前不会销毁.
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.
可以通过不将mainWindow
设置为tkinterGui
的属性来避免此问题
-即将self.mainWindow
更改为mainWindow
.这样,当run
方法在tkinterGui
线程中结束时,可以销毁mainWindow
.但是,通常可以通过使用mainWindow.after
调用来完全避免使用线程:
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()
如果要在类中定义GUI,仍然可以这样做:
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 = False
GUI = threading.Thread(target=tkinterGui)
GUI.start()
Process = threading.Thread(target=InfiniteProcess)
Process.start()
GUI.join()
Process.join()
或更简单,只需使用主线程运行GUI mainloop:
or even simpler, just use the main thread to run the GUI mainloop:
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 InfiniteProcess():
while not finish:
print("Infinite Loop")
time.sleep(3)
finish = False
Process = threading.Thread(target=InfiniteProcess)
Process.start()
mainWindow = Tk()
app = App(mainWindow)
mainWindow.mainloop()
#When the GUI is closed we set finish to "True"
finish = True
Process.join()
这篇关于线程和tkinter的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!