我有一个简单的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
答案 0 :(得分:3)
如果您触发了需要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次机会在复制粘贴中犯下愚蠢的错误,这很难追踪,并且如果您以后决定要使用进程而不是线程,则必须更改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秒的块。