wxPython,实时捕获子进程的输出

发布于 2024-11-19 23:00:57 字数 2114 浏览 2 评论 0 原文

我正在开发 wxPython 中的应用程序,它是命令行实用程序的 GUI。 GUI 中有一个文本控件,用于显示应用程序的输出。我正在使用子进程启动 shell 命令,但在它完成之前我没有得到任何输出。

我尝试了几种解决方案,但似乎都不起作用。下面是我目前使用的代码(已更新):

       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)

特别是,我需要实时输出来创建进度条。

编辑:我根据迈克·德里斯科尔的建议更改了我的代码。它有时似乎有效,但大多数时候我都会遇到以下错误之一:

(python:7698):Gtk-CRITICAL **:gtk_text_layout_real_invalidate: 断言“layout->wrap_loop_count == 0”失败

(python:7893):Gtk-警告 **:无效的文本缓冲区迭代器:要么 迭代器未初始化,或者字符/pixbufs/小部件 自创建迭代器以来,缓冲区已被修改。你必须 使用标记、字符号或行号来保留位置 跨缓冲区修改。您可以应用标签并插入标记 不会使你的迭代器无效,但任何影响的突变 “可索引”缓冲区内容(可以通过 字符偏移量)将使所有未完成的迭代器无效 分段错误(核心转储)

有任何线索吗?

I'm working on application in wxPython which is a GUI for a command line utility. In the GUI there is a text control which should display the output from the application. I'm launching the shell command using subprocess, but I don't get any output from it until it has completed.

I have tried several solutions but none of them seems to work. Below is the code I'm using at the moment (updated):

       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)

In particular I'm going to need the output in real-time to create a progress-bar.

Edit: I changed my code, based on Mike Driscoll's suggestion. It seems to work sometimes, but most of the time I'm getting one of the following errors:

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

or

(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)

Any clues?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

尬尬 2024-11-26 23:00:57

问题是因为您正在尝试 wx.Yield 并从运行进程的线程的上下文中更新输出小部件,而不是从 GUI 线程进行更新。

  1. 您是从线程运行该进程,因此不需要调用 wx.Yield,因为您没有阻塞 GUI 线程,因此任何挂起的 UI 事件都应该正常处理。

  2. 如何处理来自非 GUI 线程的打印或其他输出。

The problem is because you are trying to wx.Yield and to update the output widgets from the context of the thread running the process, instead of doing the update from the GUI thread.

  1. Since you are running the process from a thread there should be no need to call wx.Yield, because you are not blocking the GUI thread, and so any pending UI events should be processed normally anyway.

  2. Take a look at the wx.PyOnDemandOutputWindow class for an example of how to handle prints or other output that originate from a non-GUI thread.

满地尘埃落定 2024-11-26 23:00:57

这可能有点棘手,但我找到了一种方法来做到这一点,我在这里写过: 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()

本文也展示了如何重定向文本。希望这会有所帮助!

This can be a little tricky, but I figured out one way to do it which I wrote about here: http://www.blog.pythonlibrary.org/2010/06/05/python-running-ping-traceroute-and-more/

After you have set up the redirection of the text, you just need to do something like this:

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()

The article shows how to redirect the text too. Hopefully that will help!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文