我正在使用growisofs通过我的Python应用程序刻录iso。我在两个不同的文件中有两个类; GUI()(main.py)和Boxblaze()(core.py)。 GUI()构建窗口并处理所有事件和东西,Boxblaze()具有GUI()调用的所有方法。
现在当用户选择要刻录的设备和要刻录的文件时,我需要调用一个调用以下命令的方法:`
growisofs -use-the-force-luke=dao -use-the-force-luke=break:1913760 -dvd-compat -speed=2 -Z /burner/device=/full/path/to.iso
此命令应提供类似于此的输出:
Executing 'builtin_dd if=/home/nevon/games/Xbox 360 isos/The Godfather 2/alls-tgod2.iso of=/dev/scd0 obs=32k seek=0'
/dev/scd0: "Current Write Speed" is 2.5x1352KBps.
#more of the lines below, indicating progress.
7798128640/7835492352 (99.5%) @3.8x, remaining 0:06 RBU 100.0% UBU 99.8%
7815495680/7835492352 (99.7%) @3.8x, remaining 0:03 RBU 59.7% UBU 99.8%
7832862720/7835492352 (100.0%) @3.8x, remaining 0:00 RBU 7.9% UBU 99.8%
builtin_dd: 3825936*2KB out @ average 3.9x1352KBps
/dev/burner: flushing cache
/dev/burner: closing track
/dev/burner: closing disc
此命令在Boxblaze()中名为burn()的方法中运行。看起来很简单:
def burn(self, file, device):
subprocess.call(["growisofs", '-dry-run', "-use-the-force-luke=dao", "-use-the-force-luke=break:1913760", "-dvd-compat", "-speed=2", "-Z", device +'='+ file])
现在我的问题如下:
如何从输出中获得进度(括号中的百分比)并将进度条设置为“跟随”该进度?我的进度条在GUI()类中调用,如下:
get = builder.get_object
self.progress_window = get(“progressWindow”)
self.progressbar = get(“progressbar”)
我是否必须在单独的线程中运行此命令才能使GUI保持响应(以便我可以更新进度条并允许用户取消刻录)?如果是这样,我怎么能这样做,仍然可以将进度传递到进度条?
如果您有兴趣,可以使用完整代码on Launchpad。如果你安装了bazaar,只需运行:
bzr branch lp:boxblaze
哦,如果你想知道,这个应用程序只适用于Linux - 所以不要担心跨平台兼容性。
答案 0 :(得分:3)
您可以使用glib.io_add_watch()
来监视连接到子进程对象中stdout和stderr的管道的输出。
proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout_id = glib.io_add_watch(proc.stdout, glib.IO_IN|glib.IO_HUP, stdout_cb)
stderr_id = glib.io_add_watch(proc.stderr, glib.IO_IN|glib.IO_HUP, stderr_cb)
然后,当调用回调时,它应该检查条件并从管道读取所有数据并处理它以获取更新ProgressBar的信息。如果应用程序缓冲io,那么你可能不得不使用pty来欺骗它认为它连接到终端,所以它会一次输出一行。
答案 1 :(得分:1)
要获得输出,您需要使用subprocess.Popen
来电。 (stdout = subprocess.PIPE
)
(第二个问题)
除非GUI框架可以在正常循环中选择文件描述符,否则您可能需要一个单独的线程。
您可以让后台线程读取管道,处理它(以提取进度),将其传递给GUI线程。
## You might have to redirect stderr instead/as well
proc = sucprocess.Popen(command,stdout=subprocess.PIPE)
for line in proc.stdout.readlines():
## might not work - not sure about reading lines
## Parse the line to extract progress
## Pass progress to GUI thread
编辑:
我担心我不想浪费大量的CD来测试它,所以我没有运行它,但是你评论它看起来好像它没有输出信息到stdout,而是stderr。
我建议直接在命令行上运行示例命令,并将stdout和stderr重定向到不同的文件。
growisofs [options] >stdout 2>stderr
然后你可以找出stdout上出现的东西以及stderr上的内容。
如果您想要的东西是stderr,请将stdout=subprocess.PIPE
更改为stderr=subprocess.PIPE
并查看其是否有效。
EDIT2:
你没有正确使用线程 - 你应该启动它 - 不直接运行它。
此外:
gtk.gdk.threads_init()
threading.Thread.__init__(self)
非常奇怪 - 初始化调用应该在初始化程序中 - 我认为你不需要将它作为一个gtk线程吗?
调用run()方法的方式本身很奇怪:
core.Burning.run(self.burning, self.filechooser.get_filename(), self.listofdevices[self.combobox.get_active()])
通过对象调用实例方法:
self.burning.run(self.filechooser.get_filename(), self.listofdevices[self.combobox.get_active()])
(但你应该有一个__init__()
方法)
在我看来,在你走路之前,你正试图奔跑。尝试编写一些简单的线程代码,然后编写一些简单的代码来运行growisofs并解析输出,然后是一些简单的gtk +背景线程代码,然后尝试将它们组合在一起。 实际上,首先要开始编写一些简单的面向对象的代码,以便首先理解方法和对象。
e.g。您在python中创建的所有类都应该是新式类,您应该从初始化程序中调用超类初始化程序等。
答案 2 :(得分:0)
你可以通过超时来读取子进程吗?我想你可以因为my subProcess module被用作它的设计输入。你可以使用它来growiso.read(.1),然后从outdata(或者errdata)解析并显示百分比。
答案 3 :(得分:0)
您需要从单独的线程运行命令,并使用gobject.idle_add调用更新gui。现在你有一个类“燃烧”,但你使用它错了,它应该像这样使用:
self.burning = core.Burning(self.filechooser.get_filename(), self.listofdevices[self.combobox.get_active()], self.progressbar)
self.burning.start()
显然你必须修改core.Burning。 然后您将可以访问进度条,以便您可以创建这样的函数:
def set_progress_bar_fraction(self, fraction):
self.progress_bar.set_fraction(fraction)
然后,每个百分比更新都会调用它:gobject.idle_add(self.set_progress_bar_fraction, fraction)
有关线程here的pygtk的更多信息。