简体   繁体   English

需要帮助从python项目中的pygtk GUI实时捕获STDOUT

[英]Needing Help Capturing STDOUT in real-time from pygtk GUI in python project

I am working on a project in which I want to use the command line utility cdparanoia from a python pygtk GUI. 我正在一个项目中,我想从python pygtk GUI中使用命令行实用程序cdparanoia。 I'm using Glade for UI development. 我正在使用Glade进行UI开发。 I have tried importing subprocess and using subprocess.Popen. 我尝试导入子流程并使用subprocess.Popen。 It works, but it freezes my GUI (won't even allow repainting of the windows) while the process is executing. 它可以工作,但是在执行过程时冻结了我的GUI(甚至不允许重新绘制窗口)。 Not a very nice interaction for the user. 对用户来说不是一个很好的交互。 How can I prevent this behaviour? 我该如何防止这种行为? I would like put a cancel button on the window but this would work as it "freezes" the program. 我想在窗口上放置一个“取消”按钮,但这在“冻结”程序时会起作用。 Ultimately, I would like to capture stderr (as below, audio info is piped to sox via stdout) and present it in as a gtk.Expander with a similar look to Synaptic when it is installing a program with the ability of the user to see things happening in real time. 最终,我想捕获stderr(如下所示,音频信息通过stdout通过管道传输到sox)并以gtk形式呈现.Expander在安装程序时具有类似于Synaptic的外观,并且用户可以看到实时发生的事情。 Also, I would like to use the text from the progress indicator (as seen below) to build a real progress indicator widget. 另外,我想使用进度指示器中的文本(如下所示)来构建实际的进度指示器小部件。 How can I get a shell to pass info back to python in real-time rather than once the process is finished (when it gives it all as one big info dump)? 我如何获得一个shell来将信息实时传递回python,而不是一旦过程完成(当它作为一个大的信息转储将其全部提供时)?

Real-time info needing captured: 需要捕获的实时信息:

Working on me - me - DISK 01.flac
cdparanoia III release 10.2 (September 11, 2008)

Ripping from sector       0 (track  1 [0:00.00])
      to sector  325195 (track 15 [1:56.70])

outputting to stdout

 (== PROGRESS == [>                             | 004727 00 ] == :-) O ==)

Here is the code I've used so far: 这是我到目前为止使用的代码:

        quick = " -Z" if self.quick == True else ""
        command = "cdparanoia -w%s 1- -| sox -t wav - \"%s - %s - DISK %s%s.flac\"" %\
                    (
                        quick,
                        self.book_name.replace(" ", "_"),
                        self.author_name.replace(" ", "_"),
                        "0" if disc < 10 else "", 
                        disc
                    )
        print command
        shell = subprocess.Popen(command, shell=True, executable="/bin/bash",
                                    stdin=subprocess.PIPE,
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE
                                )
        data, err = shell.communicate(command)

With Thanks, Narnie 谢谢纳妮

I wrote a Python shell implementation once, and it did run wget and the actual Python console with fully functional output. 我曾经写过一个Python shell实现,它确实运行wget和具有完整功能输出的实际Python控制台。

You need to use subprocess.Popen and write directly to sys.stdout : 您需要使用subprocess.Popen并直接写入sys.stdout

process = subprocess.Popen(shlex.split(command), stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
complete = False

while True:
  output = process.stdout.read(1)

  if output == '' and process.poll() != None:
    break

  if output != '':
    sys.stdout.write(output)
    sys.stdout.flush()

If you write a GUI program which reads from a file handle you have two use a dispatcher to integrate the file descriptor events into the GUI event loop. 如果编写一个从文件句柄读取的GUI程序,则有两个使用调度程序将文件描述符事件集成到GUI事件循环中。 A general description of event loops can be found at Wikipedia . 事件循环的一般描述可以在Wikipedia上找到。 The specific description for Gtk+ can be found in the reference . 有关Gtk +的具体说明,请参见参考资料

Solution for your problem: use the function g_io_add_watch to integrate your action into the main event loop. 解决问题的方法:使用函数g_io_add_watch将您的操作集成到主事件循环中。 Here is an example in C. Python should be analogous. 是C语言中的一个示例。Python应该是类似的。

Yes there are 2 issues here. 是的,这里有2个问题。 The first is that you'll need to specify a read timeout, so that you don't block until the sub process is finished. 首先,您需要指定读取超时,以便在子过程完成之前不会阻塞。 The second is that there is probably buffering happening that is not desirable. 第二个原因是可能发生不希望发生的缓冲。

To address the first issue, and read from the sub process asynchronously you could try my subProcess module, with a timeout: http://www.pixelbeat.org/libs/subProcess.py Note this is simple but also old and linux only. 要解决第一个问题,并以异步方式从子流程中读取内容,可以尝试使用超时的subProcess模块​​: http ://www.pixelbeat.org/libs/subProcess.py注意,这很简单,但也很旧,并且仅适用于linux。 It was used as a basis for the new python subprocess module, so you'd be better to go with that if you need portability. 它被用作新的python子进程模块的基础,因此如果需要可移植性,则最好使用它。

To understand/control any additional buffering which may happen, see: http://www.pixelbeat.org/programming/stdio_buffering/ 要了解/控制可能发生的任何其他缓冲,请访问: http : //www.pixelbeat.org/programming/stdio_buffering/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM