如何在wxPython TextCtrl中捕获在单独进程中运行的shell脚本的输出?

一个长时间运行的shell脚本生成stdout和stderr,我想在GUI中的textctrl上显示它.这可以使用线程并将GUI线程与shell脚本的线程分开.然而,当我实现多处理时,我遇到了障碍.这是我的下载代码:#!/usr/bin/env pythonimpor...

一个长时间运行的shell脚本生成stdout和stderr,我想在GUI中的textctrl上显示它.这可以使用线程并将GUI线程与shell脚本的线程分开.然而,当我实现多处理时,我遇到了障碍.这是我的下载代码:

#!/usr/bin/env python

import wx
import sys, subprocess
from multiprocessing import Process, Queue
from Queue import Empty

class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        wx.Frame.__init__(self, *args, **kwds)

        self.button = wx.Button(self, -1 , "Run")
        self.output = wx.TextCtrl(self, -1, '', style=wx.TE_MULTILINE|                                                      wx.TE_READONLY|wx.HSCROLL)

        self.Bind(wx.EVT_BUTTON, self.OnButton, self.button)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.output, -1, wx.EXPAND, 0)
        sizer.Add(self.button)
        self.SetSizerAndFit(sizer)
        self.Centre()

    def OnButton(self, event):
        numtasks = 4 # total number of tasks to run
        numprocs = 2 # number of processors = number of parallel tasks
        work_queue = Queue()
        for i in xrange(numtasks):
             work_queue.put(i)
        processes = [Process(target=self.doWork, args=(work_queue, ))
                     for i in range(numprocs)]
        for p in processes:
            p.daemon = True
            p.start()

    def doWork(self, work_queue):
        while True:
            try:
                x = work_queue.get(block=False)
                self.runScript(x)
            except Empty:
                print "Queue Empty"
                break

    def runScript(self, taskno):
        print '## Now Running: ', taskno
        command = ['./script.sh']  
        proc = subprocess.Popen(command, shell=True, 
                                         stdout=subprocess.PIPE, 
                                         stderr=subprocess.STDOUT)
        while True:
            stdout = proc.stdout.readline()
            if not stdout:
                break
            #sys.stdout.flush() #no need for flush, apparently it is embedded in the multiprocessing module
            self.output.AppendText(stdout.rstrip()) #this is the part that doesn't work.

if __name__ == "__main__":
    app = wx.App(0)
    frame = MyFrame(None, title="shell2textctrl", size=(500,500))
    frame.Show(True)
    app.MainLoop()

我已经根据别人的建议尝试了很多解决方案.其中包括:使用wx.CallAfter或wx.lib.delayedresult使GUI响应;几个线程配方(例如,wxApplication Development Cookbook,threadpool,其他……)并让multiprocess()从一个单独的线程运行;重新定义sys.stdout.write以写入textctrl;等等.他们都没有成功.任何人都可以提供解决方案和工作代码吗?您可以在这里使用此脚本编写我遗忘的人:

#!/bin/tcsh -f
@ i = 1
while ($i <= 20)
 echo $i
 @ i += 1
 sleep 0.2
end

解决方法:

我不知道这是否会对你有所帮助,但我在这里使用子进程有这样的例子:

http://www.blog.pythonlibrary.org/2010/06/05/python-running-ping-traceroute-and-more/

请参阅pingIP和tracertIP方法.如果您的shell脚本是用Python编写的,那么您可以添加某种类型的生成器,就像我在该文章中使用的那些发布回GUI一样.您可能已经阅读过LongRunningProcess wiki文章,但我接受了这个并在此处制作了自己的教程:

http://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/

本文标题为:如何在wxPython TextCtrl中捕获在单独进程中运行的shell脚本的输出?

基础教程推荐