4

我正在使用 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])

现在我的问题如下:

  1. 如何从输出中获取进度(括号中的百分比)并将进度条设置为“跟随”该进度?我的进度条在 GUI() 类中调用,如下所示:

    获取 = builder.get_object

    self.progress_window = get("progressWindow")

    self.progressbar = get("进度条")

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


如果您有兴趣,可以在 Launchpad 上找到完整的代码。如果您安装了集市,只需运行:

bzr branch lp:boxblaze

哦,如果你想知道,这个应用程序只适用于 Linux - 所以不要担心跨平台兼容性。

4

4 回答 4

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 来欺骗它认为它已连接到终端,因此它会一次输出一行。

于 2009-09-28T01:28:08.540 回答
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 重定向到不同的文件。

growisofs [options] >stdout 2>stderr

然后,您可以计算出哪些内容出现在 stdout 上,哪些内容出现在 stderr 上。

如果您想要的东西出现在 stderr 上,请更改stdout=subprocess.PIPEstderr=subprocess.PIPE,看看是否效果更好。

编辑2:

您没有正确使用线程-您应该启动它-而不是直接运行它。

还:

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+background 线程代码,然后再尝试将它们组合在一起。其实先开始写一些简单的面向对象的代码,让你先了解方法和对象。

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

于 2009-08-16T12:37:23.423 回答
0

您可以通过超时从子进程读取吗?我想你可以,因为我的 subProcess 模块被用作它的设计输入。您可以使用它来增长iso.read(.1),然后解析并显示来自 outdata(或者可能是 errdata)的百分比。

于 2009-08-16T12:38:47.090 回答
0

您需要从单独的线程运行命令,并使用 gobject.idle_add 调用更新 gui。现在你有一个“Burning”类,但是你用错了,应该这样使用:

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)

有关 pygtk 的更多信息,请点击此处

于 2009-08-24T04:44:34.703 回答