需要帮助从 python 项目中的 pygtk GUI 实时捕获 STDOUT
我正在开发一个项目,我想在 python pygtk GUI 中使用命令行实用程序 cdparanoia。我正在使用 Glade 进行 UI 开发。我尝试导入 subprocess 并使用 subprocess.Popen。它可以工作,但在进程执行时它会冻结我的 GUI(甚至不允许重新绘制窗口)。对于用户来说这不是一个很好的交互。我怎样才能防止这种行为?我想在窗口上放置一个取消按钮,但这会起作用,因为它会“冻结”程序。最终,我想捕获stderr(如下所示,音频信息通过stdout传输到sox)并将其呈现为gtk.Expander,当它安装程序时,用户能够看到它,其外观与Synaptic类似事情是实时发生的。另外,我想使用进度指示器中的文本(如下所示)来构建真正的进度指示器小部件。如何让 shell 实时将信息传递回 python,而不是在进程完成后(当它将所有信息作为一个大的信息转储提供时)?
需要捕获的实时信息:
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 ==)
这是我迄今为止使用的代码:
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)
谢谢, 纳尼
I am working on a project in which I want to use the command line utility cdparanoia from a python pygtk GUI. I'm using Glade for UI development. I have tried importing subprocess and using subprocess.Popen. It works, but it freezes my GUI (won't even allow repainting of the windows) while the process is executing. 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. 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)?
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我曾经编写过一个 Python shell 实现,它确实运行了 wget 和具有完整功能输出的实际 Python 控制台。
您需要使用
subprocess.Popen
并直接写入sys.stdout
:I wrote a Python shell implementation once, and it did run
wget
and the actual Python console with fully functional output.You need to use
subprocess.Popen
and write directly tosys.stdout
:如果您编写一个从文件句柄读取的 GUI 程序,则需要使用调度程序将文件描述符事件集成到 GUI 事件循环中。事件循环的一般描述可以在 Wikipedia 中找到。 Gtk+的具体描述可以参见参考。
问题的解决方案:使用函数
g_io_add_watch
将您的操作集成到主事件循环中。 这里是一个 C 语言的示例。Python 应该是类似的。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. A general description of event loops can be found at Wikipedia. The specific description for Gtk+ can be found in the reference.
Solution for your problem: use the function
g_io_add_watch
to integrate your action into the main event loop. Here is an example in C. Python should be analogous.是的,这里有两个问题。
首先,您需要指定读取超时,以便
在子进程完成之前您不会阻塞。
第二个是可能发生不希望的缓冲。
解决第一个问题,从子进程异步读取
你可以尝试我的 subProcess 模块,但有超时:
http://www.pixelbeat.org/libs/subProcess.py
请注意,这很简单,但也很旧并且仅限 Linux。
它被用作新的 python subprocess 模块的基础,
所以如果你需要便携性,你最好选择它。
要了解/控制可能发生的任何额外缓冲,请参阅:
http://www.pixelbeat.org/programming/stdio_buffering/
Yes there are 2 issues here.
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.
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.
To understand/control any additional buffering which may happen, see:
http://www.pixelbeat.org/programming/stdio_buffering/