我需要从Tkinter GUI能够启动长时间运行的Linux脚本,但同时我希望能够启用停止按钮,以便我可以停止该过程。 Tkinter和popen都不是线程安全的。我想只是将popen函数放在一个线程中,或者只是在一个线程中启用一个按钮。我目前正在使用Red Hat Linux 5.9,它使用的是Python 2.4.3,但我可以在线使用以后的版本。在程序中,下面注意我将开始按钮重新配置为停止按钮,但这不起作用,因为启动按钮功能处于活动状态,但它表示我的意图。请注意,stop函数只对子项执行os.kill()。
#!/usr/bin/python
import subprocess
import sys
import Tkinter
import tkMessageBox
import signal
import os
import time
class popentest:
def __init__(self):
self.mainWindow = Tkinter.Tk()
def __createUI(self, mainWindow):
mainWindow.protocol("WM_DELETE_WINDOW", self.OnExitWindow)
## Local variables.
sleep=5
iter=5
self.pid=0
self.mainWindow.title("Test popen")
self.start=Tkinter.Button(mainWindow, text=u"Start", command=self.onStart)
self.start.grid()
self.kwit = Tkinter.Button(mainWindow,text=u"Quit !",
command=self.onQuit)
self.kwit.grid()
self.lIter=Tkinter.Label(mainWindow, text="Iterations: ")
self.iterE=Tkinter.Entry(mainWindow, width=2)
self.lSleep = Tkinter.Label(mainWindow, text="Sleep time")
self.sleepEntry = Tkinter.Entry(mainWindow, width=3)
self.lIter.grid()
self.iterE.grid()
self.lSleep.grid()
self.sleepEntry.grid()
self.iterE.insert(0, str(iter))
self.sleepEntry.insert(0,str(sleep))
def startPopen(self):
self.__createUI(self.mainWindow)
self.mainWindow.mainloop()
def execute(self, numIters, sleep):
self.p = subprocess.Popen(['./testpopen.sh',str(numIters), str(sleep)], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
self.pid=self.p.pid
print str(self.p.pid)+" started"
for line in iter(self.p.stdout.readline, ''):
print line
self.p.stdout.close()
self.pid=0
self.start.configure(text=u"Start", command=self.onStart)
def onStart(self):
numIters=self.iterE.get()
sleep=self.sleepEntry.get()
if not numIters.isdigit():
tkMessageBox.showerror(
"invalid entry",
"Iteration (%s)must be numeric\n" % numIters)
return
elif not sleep.isdigit():
tkMessageBox.showerror(
"invalid entry",
"Sleep(%s) is not numeric\n" % sleep)
return
numIters=int(numIters)
sleep=int(sleep)
if numIters <= 0 or sleep <=0 :
tkMessageBox.showerror(
"invalid entry",
"Either iteration (%d) or sleep(%d) is <= 0\n" % (numIters, sleep))
else:
print "configuring start to stop"
self.start.configure(text=u"Stop", command=self.onStop)
time.sleep(1)
self.execute(numIters, sleep)
def onStop(self):
print "configuring stop to start"
os.kill(p.pid, signal.SIGTERM)
self.start.configure(text=u"Start", command=self.onStart)
def OnExitWindow(self):
if self.pid != 0 :
os.kill(self.pid, signal.SIGKILL)
self.mainWindow.destroy()
def onQuit(self):
if self.pid != 0 :
os.kill(self.pid, signal.SIGKILL)
self.mainWindow.destroy()
if __name__ == "__main__":
remote = popentest()
remote.startPopen()
答案 0 :(得分:1)
您可以使用Popen开始您的流程,使用非阻塞管道进行通信 使用该过程 - 这样,您可以异步接收其输出。我已经 使用了Popen的增强版本,代码来自ActiveState Python cookbook配方。 我再也找不到网上的食谱了,但是因为我还有代码我在这里贴了它:
https://gist.github.com/mguijarr/6874724
然后,在您的Tkinter代码中,您可以使用计时器定期检查 进程状态(终止或不终止)并获得输出:
self.p = EnhancedPopen.Popen(['./testpopen.sh',str(numIters), str(sleep)],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True,universal_newlines=True)
self.mainWindow.after(100, self.check_process)
def check_process(self):
# get stdout output
output = EnhancedPopen.recv_some(self.p, e=0, stderr=0)
...
if self.p.poll() is not None:
# process terminated
...
return
# set timer again (until process exits)
self.mainWindow.after(100, self.check_process_output)