停止线程并避免';运行时错误';在python中使用线程和tkinter模块?
我已经在网上讨论了多种解决方案,但它们需要大量的代码,一旦扩展,这些代码可能会让人困惑。有没有一种简单的方法可以停止线程并避免停止线程并避免';运行时错误';在python中使用线程和tkinter模块?,python,multithreading,tkinter,python-multithreading,software-design,Python,Multithreading,Tkinter,Python Multithreading,Software Design,我已经在网上讨论了多种解决方案,但它们需要大量的代码,一旦扩展,这些代码可能会让人困惑。有没有一种简单的方法可以停止线程并避免运行时错误:线程只能启动一次,以便无限次地调用线程。以下是我的代码的简单版本: import tkinter import time import threading def func(): entry.config(state='disabled') label.configure(text="Standby for seconds") t
运行时错误:线程只能启动一次,以便无限次地调用线程。以下是我的代码的简单版本:
import tkinter
import time
import threading
def func():
entry.config(state='disabled')
label.configure(text="Standby for seconds")
time.sleep(3)
sum = 0
for i in range(int(entry.get())):
time.sleep(0.5)
sum = sum+i
label.configure(text=str(sum))
entry.config(state='normal')
mainwindow = tkinter.Tk()
mainwindow.title('Sum up to any number')
entry = tkinter.Entry(mainwindow)
entry.pack()
label = tkinter.Label(mainwindow, text = "Enter an integer",font=("Arial",33))
label.pack()
print(entry.get())
button = tkinter.Button(mainwindow, text="Press me", command=threading.Thread(target=func).start)
button.pack()
可以从其他线程调用tkinter小部件上的修改,这些修改将在主线程可用时立即发生。如果调用修改的后台线程休眠,而主线程仅在mainloop
中,我们可以模拟应用程序中的暂停,而不会像问题所针对的那样阻塞主线程
然后,我们可以对线程
进行子类化,以生成一个线程,该线程运行自己的循环,并且即使在其目标完成后仍保持已启动
,以便我们可以调用其目标任意多次。我们甚至可以通过使用守护进程
模式和尝试
-除
块外,将后台线程中发生的错误传递给用户,并在不挂起应用程序的情况下优雅地退出线程
thread.do
充当一个开关,我们可以在lambda
中设置该开关,以便在按下按钮时在线程上运行func
。这在主线程和后台线程之间实现了一个廉价的消息传递系统,我们可以通过少量额外代码来扩展该系统,以允许使用参数调用func
,并从中返回值
import threading, time, tkinter, sys
class ImmortalThread(threading.Thread):
def __init__(self, func):
super().__init__(daemon=True)
self.func = func
self.do = tkinter.BooleanVar()
def run(self):
while True:
if self.do.get():
try:
self.func()
self.do.set(False)
except:
print("Exception on", self, ":", sys.exc_info())
raise SystemExit()
else:
# keeps the thread running no-ops so it doesn't strip
time.sleep(0.01)
def func():
entry.config(state='disabled')
label.configure(text="Standby for seconds")
time.sleep(3)
sum = 0
for i in range(int(entry.get())):
time.sleep(0.5)
sum = sum+i
label.configure(text=str(sum))
entry.config(state='normal')
mainwindow = tkinter.Tk()
mainwindow.title("Sum up to any number")
entry = tkinter.Entry(mainwindow)
entry.pack()
label = tkinter.Label(mainwindow, text="Enter an integer", font=("Arial", 33))
label.pack()
thread = ImmortalThread(func)
thread.start()
button = tkinter.Button(mainwindow, text="Press me", command=lambda: thread.do.set(True))
button.pack()
mainwindow.mainloop()
虽然这是一种简单的方法,可以用更少的代码行完成任务。我无法使用.join()
方法。但是,该应用程序似乎没有创建任何新线程。这一点通过threading.active_counts()
方法显而易见。代码如下:
import tkinter, threading, time
def calc():
entry.config(state='disabled')
label.configure(text="Standby for 3 seconds")
time.sleep(3)
sum = 0
for i in range(int(entry.get())):
time.sleep(0.5)
sum = sum+i
labelnum.configure(text=str(sum))
button.config(state='normal')
label.configure(text="Sum up to any number")
entry.config(state='normal')
def func():
t = threading.Thread(target=calc)
t.start()
#del t
print('Active threads:',threading.active_count())
mainwindow = tkinter.Tk()
mainwindow.title('Sum up to any number')
entry = tkinter.Entry(mainwindow)
entry.pack()
label = tkinter.Label(mainwindow, text = "Enter an integer",font=("Arial",33))
label.pack()
labelnum = tkinter.Label(mainwindow, text="",font=('Arial',33))
labelnum.pack()
button = tkinter.Button(mainwindow, text="Press me", command=func)
button.pack()
mainwindow.mainloop()
您根本不能使用这种方法:Tkinter对象只能从事件分派(例如,mainloop
)线程中使用。这是否回答了您的问题?代码避免了“运行时错误”,但仍然不允许重复求和。我在下面贴了一个答案,我想你应该看看。代码可以按照我的要求完成任务,但它只是一次又一次地创建线程,我真的不知道每次求和时创建线程是否是一种好的做法。也许你会有一个杀死线程的主意?谢谢