wxPython,实时捕获子进程输出

2 投票
2 回答
3148 浏览
提问于 2025-04-16 21:24

我正在用wxPython开发一个应用程序,这个程序是一个命令行工具的图形界面。在这个图形界面里,有一个文本框用来显示应用程序的输出。我是通过一个叫subprocess的工具来启动命令行指令的,但我发现只有在命令执行完毕后,才会看到输出。

我尝试了好几种解决办法,但都没有成功。下面是我现在用的代码(更新过的):

       def onOk(self,event):        
        self.getControl('infotxt').Clear()
        try:
            thread = threading.Thread(target=self.run)
            thread.setDaemon(True)
            thread.start()

        except Exception:
            print 'Error starting thread'    

    def run(self):    
        args = dict()
        # creating a command to execute...

        cmd = ["aplcorr", "-vvfile", args['vvfile'], "-navfile", args['navfile'], "-lev1file", args['lev1file'], "-dem", args['dem'], "-igmfile", args['outfile']]

        proc = subprocess.Popen(' '.join(cmd), shell=True, stdout=subprocess.PIPE, stderr.subprocess.PIPE)         

        print
        while True:
            line = proc.stdout.readline()
            wx.Yield()
            if line.strip() == "":
                pass
            else:                
                print line.strip()                
            if not line: break
        proc.wait()

class RedirectInfoText:
    """ Class to redirect stdout text """
    def __init__(self,wxTextCtrl):
        self.out=wxTextCtrl

    def write(self,string):
        self.out.WriteText(string)

class RedirectErrorText:
    """ Class to redirect stderr text """    
    def __init__(self,wxTextCtrl):
        self.out.SetDefailtStyle(wx.TextAttr())
        self.out=wxTextCtrl

    def write(self,string):
        self.out.SetDefaultStyle(wx.TextAttr(wx.RED))
        self.out.WriteText(string)

特别是,我需要实时看到输出,这样才能创建一个进度条。

编辑:我根据Mike Driscoll的建议修改了我的代码。这个方法有时候能工作,但大多数时候我会遇到以下错误:

(python:7698): Gtk-CRITICAL **: gtk_text_layout_real_invalidate: assertion `layout->wrap_loop_count == 0' failed

或者

(python:7893): Gtk-WARNING **: Invalid text buffer iterator: either the iterator is uninitialized, or the characters/pixbufs/widgets in the buffer have been modified since the iterator was created. You must use marks, character numbers, or line numbers to preserve a position across buffer modifications. You can apply tags and insert marks without invalidating your iterators, but any mutation that affects 'indexable' buffer contents (contents that can be referred to by character offset) will invalidate all outstanding iterators Segmentation fault (core dumped)

有没有什么线索?

2 个回答

2

这可能有点复杂,但我找到了一种方法,可以在这里查看我写的内容:http://www.blog.pythonlibrary.org/2010/06/05/python-running-ping-traceroute-and-more/

在你设置好文本重定向之后,只需要像这样做:

def pingIP(self, ip):
    proc = subprocess.Popen("ping %s" % ip, shell=True,
                            stdout=subprocess.PIPE)
    print
    while True:
        line = proc.stdout.readline()
        wx.Yield()
        if line.strip() == "":
            pass
        else:
            print line.strip()
        if not line: break
    proc.wait()

这篇文章也展示了如何重定向文本。希望这能帮到你!

3

这个问题的原因是你在一个线程中运行进程时,试图使用 wx.Yield 来更新输出的控件,但实际上应该在GUI线程中进行更新。

  1. 因为你是在一个线程中运行这个进程,所以其实不需要调用 wx.Yield。这样做是因为你并没有阻塞GUI线程,所以任何待处理的用户界面事件应该会正常处理。

  2. 你可以看看 wx.PyOnDemandOutputWindow 这个类,它提供了一个例子,教你如何处理来自非GUI线程的打印或其他输出。

撰写回答