使用Tkinter模块的GUI“按钮”管理脚本执行
有一个这样的脚本:
import sys, Tkinter
def myScript():
...
...
def runScript():
while 1:
myScript()
我想用Tkinter模块中的“按钮”来管理它。
if __name__ == '__main__':
win = Frame ()
win.pack ()
Label(win, text='Choose following action', font=("Helvetica", 16), width=70, height=20).pack(side=TOP)
Button(win, text='Start script', width=20, height=3, command=runScript).pack(side=LEFT)
Button(win, text='Stop script', width=20, height=3, command=sys.exit).pack(side=LEFT)
Button(win, text='Quit', width=15, height=2, command=win.quit).pack(side=RIGHT)
mainloop()
当我点击“开始脚本”按钮时,我的脚本成功启动并运行(是个无限循环),但是当我想用“停止脚本”按钮来停止它时,我做不到,因为主窗口和按钮都变得不可用(显示“没有响应”)。
我需要做什么改变才能正确使用这两个按钮呢?
2 个回答
-2
使用这个:
import sys
from Tkinter import *
import tkMessageBox as tkmsg
win = None
def myScript():
pass
def runScript():
global win
while 1:
win.update()
pass
def btnStop_Click():
tkmsg.showinfo("Stopped", "Stopped")
sys.exit
if __name__ == '__main__':
global win
win = Frame ()
win.pack ()
Label(win, text='Choose following action', font=("Helvetica", 16), width=70, height=20).pack(side=TOP)
Button(win, text='Start script', width=20, height=3, command=runScript).pack(side=LEFT)
Button(win, text='Stop script', width=20, height=3, command=btnStop_Click).pack(side=LEFT)
Button(win, text='Quit', width=15, height=2, command=win.quit).pack(side=RIGHT)
mainloop()
2
问题在于,脚本的执行被认为是被阻塞的,所以它一直在运行时,控制权不会返回到图形界面(GUI),这样就无法继续处理任何外部命令来停止它。要解决这个问题,你需要使用线程。最好的方法是让你的脚本方法继承自 threading.Thread
,并重写 .run()
方法来执行你的脚本。这样做的代码看起来是这样的:
import threading
class MyScript(threading.Thread):
def __init__(self):
super(MyScript, self).__init__()
self.__stop = threading.Event()
def stop(self):
self.__stop.set()
def stopped(self):
return self.__stop.isSet()
def run(self):
while not self.stopped():
# Put your script execution here
print "running"
接下来,你可以设置一个全局变量或类变量来跟踪当前是否有线程在运行(如果你希望用户能够运行多个脚本实例,可能需要以不同的方式处理这个问题),以及启动和停止线程的方法。我建议使用类变量,因为你的应用本身就是一个类,但这取决于你。
script_thread = None
def startScript():
global script_thread
# If we don't already have a running thread, start a new one
if not script_thread:
script_thread = MyScript()
script_thread.start()
def stopScript():
global script_thread
# If we have one running, stop it
if script_thread:
script_thread.stop()
script_thread = None
然后,你可以将这些方法绑定到你的按钮上。我不太确定你的应用结构是怎样的(看起来你是从 Tkinter 导入了所有内容,或者是对 Tkinter.Tk() 实例进行了子类化)。不过,为了实现你所提议的功能,你需要使用线程来避免阻塞的情况。