Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Tkinter、Popen和threads_Python_Linux_Multithreading_Tkinter - Fatal编程技术网

Python Tkinter、Popen和threads

Python Tkinter、Popen和threads,python,linux,multithreading,tkinter,Python,Linux,Multithreading,Tkinter,我需要从Tkinter GUI启动一个长时间运行的Linux脚本,但同时我希望能够启用一个停止按钮,这样我就可以停止进程。Tkinter和popen都不是线程安全的。我想简单地将popen函数放在线程中,或者可能只是在线程中启用一个按钮。我目前正在使用Red Hat Linux 5.9,它使用Python 2.4.3,但我可以在线使用更高版本。在下面的程序中,请注意,我将“开始”按钮重新配置为“停止”按钮,但这不起作用,因为“开始”按钮功能处于活动状态,但它表明了我的意图。请注意,stop函数只

我需要从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()    
#/usr/bin/python
导入子流程
导入系统
进口Tkinter
导入tkMessageBox
输入信号
导入操作系统
导入时间
等级popentest:
定义初始化(自):
self.mainWindow=Tkinter.Tk()
def__createUI(自身,主窗口):
协议(“WM\u DELETE\u WINDOW”,self.OnExitWindow)
##局部变量。
睡眠=5
iter=5
self.pid=0
self.mainWindow.title(“测试popen”)
self.start=Tkinter.Button(主窗口,文本=u“start”,命令=self.onStart)
self.start.grid()
self.kwit=Tkinter.Button(主窗口,文本=u“退出!”,
command=self.onQuit)
self.kwit.grid()
self.lill=Tkinter.Label(主窗口,text=“迭代:”)
self.iterE=Tkinter.Entry(主窗口,宽度=2)
self.lSleep=Tkinter.Label(主窗口,text=“睡眠时间”)
self.sleepEntry=Tkinter.Entry(主窗口,宽度=3)
self.l.grid()
self.iterE.grid()
self.lSleep.grid()
self.sleepEntry.grid()
自我测试插入(0,str(iter))
self.sleepEntry.insert(0,str(sleep))
def STARTOPEN(自):
self.\uuu createUI(self.main窗口)
self.mainWindow.mainloop()
def执行(自身、numIters、睡眠):
self.p=subprocess.Popen(['./testpopen.sh',str(numIters),str(sleep)],stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)
self.pid=self.p.pid
打印str(self.p.pid)+“已启动”
对于iter中的线路(self.p.stdout.readline“”):
打印行
self.p.stdout.close()
self.pid=0
self.start.configure(text=u“start”,command=self.onStart)
def onStart(自启动):
numIters=self.iterE.get()
sleep=self.sleepEntry.get()
如果不是numIters.isdigit():
tkMessageBox.showerror(
“无效条目”,
迭代(%s)必须是数字\n“%numIters”
返回
elif not sleep.isdigit():
tkMessageBox.showerror(
“无效条目”,
睡眠(%s)不是数字\n“%Sleep”
返回
numIters=int(numIters)
sleep=int(睡眠)

如果numIters您可以使用Popen启动进程,使用非阻塞管道进行通信 通过该流程,您可以异步接收其输出。我已经 使用了增强版的Popen,代码来自ActiveState Python食谱。 我在网上再也找不到配方了,但由于我仍然有代码,我将其粘贴到了这里:

然后,在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)

谢谢我看看能不能试试。我受到公司规定的限制,不能安装未经批准的软件包,但这应该可以。问题是我需要一个激活的按钮,这样用户就可以终止进程。这可能就足够了。我也在下面发布另一个解决方案。我将EnhancedOpen和上面的代码合并到我的测试程序中,它工作得非常完美。我应该能够把这两个生产计划没有问题。再次感谢您发布本文。太好了:)我为您感到高兴。为了避免阻塞GUI;你可以