2009-08-16 119 views
2

我正在使用growisofs来通过我的Python应用程序来刻录iso。我在两个不同的文件中有两个类。 GUI()(main.py)和Boxblaze()(core.py)。 GUI()构建窗口并处理所有事件和事物,而Boxblaze()具有GUI()调用的所有方法。subprocess.call管道输出到进度条

现在,当用户选择了设备与燃烧,并要刻录的文件,我需要调用调用以下命令的方法:`

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

现在我的问题有以下几点:

  1. 我怎样才能从输出(括号内百分比)的进展,并有我的进度条设定“跟随”那个进展?我的进度条是所谓的GUI()类,因为这样的:

    GET = builder.get_object

    self.progress_window = GET( “progressWindow”)

    self.progressbar = GET(“进度“)

  2. 我必须在单独的线程中运行此命令才能使GUI保持响应(以便我可以更新进度栏并允许用户在需要时取消刻录)?如果是这样,我该怎么做,仍然能够将进度传递给进度条?如果你有兴趣


的完整代码,请on Launchpad。如果您已经安装了集市,只需要运行:

bzr branch lp:boxblaze 

哦,如果你想知道,这个应用程序只能在Linux下工作 - 所以不要担心跨平台的兼容性。

回答

1

要获得输出,您需要使用subprocess.Popen调用。 (stdout = subprocess.PIPE

(第二个问题)

你可能需要一个单独的线程,除非GUI框架可以正常循环FileDescriptor的选择。

你可以有一个后台线程读取管道,处理它(提取进度),传递给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重定向到不同的文件。

growisofs [options] >stdout 2>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 +后台线程代码,然后尝试将它们结合在一起。实际上,首先开始写一些简单的面向对象的代码,以便你首先理解方法和对象。

例如您在python中创建的所有类应该是新式类,您应该从您的初始化程序调用超类初始化程序等。

+0

我不知道我已经完全明白了什么是你的意思。这就是我一直试图实现它(http://pastebin.com/m6b1bdff6),但它并不完全似乎工作,因为我得到(到终端)的唯一输出: 的/ dev/scd0:“当前写入速度”为2.5x1352KBps。 – 2009-08-16 13:21:17

+0

看来,我正在寻找的信息确实来自stderr。但是,现在看来我的解析不起作用,因为所有内容都会打印到屏幕上(请参阅pastebin链接)。 GUI仍然冻结。 core.py→http://pastebin.com/m586398c8 main.pu→http://pastebin.com/m28658de 另请注意,您实际上可以向growisofs命令添加-dry-run标志以尝试它不浪费DVD。 要看到整个事情,只需要运行: 的bzr分支LP:boxblaze – 2009-08-17 06:30:34

+0

噢,对不起,我忘了,包括运行我的应用程序的输出。那就是: http://pastebin.com/m6e55585a – 2009-08-17 06:31:40

0

您是否可以通过超时读取子进程?我想你可以这样做,因为my subProcess module被用作它的设计输入。您可以使用它来growiso.read(.1),然后解析并显示outdata(或可能errdata)的百分比。

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) 

然后每个更新调用它是这样的:与线程here PyGTK的gobject.idle_add(self.set_progress_bar_fraction, fraction)

更多信息。

2

您可以使用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) 

然后当回调被调用时就应该检查的条件,并读取从管道中的所有数据,并对其进行处理,以获得信息来更新进度。如果应用程序缓冲io,那么你可能不得不使用一个pty来欺骗它,认为它连接到一个终端,所以它会一次输出一行。