我有一个简单的Tkinter gui,上面有大约20个按钮。当我点击一个按钮,脚本运行大约5分钟。在此期间,我必须等到脚本停止运行才单击其他按钮。是否有方法设置窗口,以便在第一个单击脚本运行时单击其他按钮?
from Tkinter import *
import Tkinter as tk
import time
def function1():
time.sleep(60)
print 'function1'
def function2():
time.sleep(60)
print 'function2'
root = Tk()
w = 450 # width for the Tk root
h = 500# height for the Tk root
frame = Frame(root, width=w,height =h)
button1=Button(frame, text = 'function 1',fg='black',command=function1).grid(row=1,column=1)
button2=Button(frame, text = 'function 2',fg='black',command=function2).grid(row=1,column=2)
frame.pack()
root.mainloop()
我希望在function2
还在运行时能够单击function1
发布于 2018-09-08 18:24:04
如果触发一个需要1分钟才能运行的回调,则在1分钟内不会返回主循环,因此GUI无法响应任何内容。
对此有两种常见的解决办法。
第一个是使用后台线程:
def function1():
time.sleep(60)
print 'function1'
def function1_background():
t = threading.Thread(target=function1)
t.start()
button1 = Button(frame, text='function 1', fg='black', command=function1_background)
这很简单,但只有在您的代码纯粹是做后台工作时才能工作,而不涉及任何tkinter小部件。
这里唯一的问题是,您必须def
20个额外的函数。你不想重复那么多--这是80行重复的样板代码,妨碍了看到重要的代码,还有20次机会在复制粘贴中制造一个愚蠢的bug,这是很难找到的,如果你以后决定要进程而不是线程,那么就必须改变20个地方,这样工作就能更好地并行,或者一个有后台任务排队的4个线程池。
你可以用几种不同的方法解决这个问题。有关更深入的解释,请参见this question,但简而言之,您可以让Python为您做一些重复的工作。
您可以def
一个帮助函数:
def background(func):
t = threading.Thread(target=func)
t.start()
…然后是lambda
20单独的函数:
button1 = Button(frame, text='function 1', fg='black', command=lambda: background(function1))
或者,您可以使用partial
部分应用该函数。
button1 = Button(frame, text='function 1', fg='black', command=functools.partial(background, function1))
或者,如果您不想调用除后台之外的函数,可以编写一个装饰器并在def
时将其应用于每个函数:
def background(func):
@functools.wraps(func)
def wrapper():
t = threading.Thread(target=func)
t.start()
return wrapper
@background
def function1():
time.sleep(60)
print 'function1'
如果您不能使用线程(例如,因为后台工作涉及修改tkinter小部件),则可选择的方法是重构代码,使其不再是一个1分钟的单块任务,而是一组单独的任务,每个任务占用一秒的时间,并安排下一部分:
def function1(count=60):
if count > 0:
time.sleep(0.1)
frame.after(0, function1, count-0.1)
else:
print 'function1'
button1 = Button(frame, text='function 1', fg='black', command=function1)
如果你能找到办法的话,这总是有效的。您的实际工作可能不像sleep(60)
那样容易划分为0.1秒的块。
https://stackoverflow.com/questions/52240652
复制相似问题