Требуется помощь Захват STDOUT в реальном времени из графического интерфейса pygtk в проекте python - PullRequest
1 голос
/ 06 мая 2011

Я работаю над проектом, в котором я хочу использовать утилиту командной строки cdparanoia из python pygtk GUI.Я использую Glade для разработки пользовательского интерфейса.Я попытался импортировать подпроцесс и использовать подпроцесс. Открыть.Это работает, но он замораживает мой графический интерфейс (даже не позволяет перерисовывать окна) во время выполнения процесса.Не очень приятное взаимодействие для пользователя.Как я могу предотвратить это поведение?Я хотел бы поставить кнопку отмены в окне, но это будет работать, поскольку он "замораживает" программу.В конечном счете, я хотел бы захватить stderr (как показано ниже, аудиоинформация передается в sox через stdout) и представить его как gtk.Expander с похожим на Synaptic внешним видом, когда он устанавливает программу с возможностью просмотра пользователемвещи происходят в реальном времени.Кроме того, я хотел бы использовать текст из индикатора прогресса (как показано ниже) для создания виджета индикатора реального прогресса.Как получить оболочку для передачи информации обратно в 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)

С благодарностью, Нарни

Ответы [ 3 ]

2 голосов
/ 06 мая 2011

Я однажды написал реализацию оболочки Python, и она действительно запустила wget и реальную консоль Python с полнофункциональным выводом.

Вам нужно использовать 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()
1 голос
/ 06 мая 2011

Если вы пишете программу с графическим интерфейсом, которая читает из дескриптора файла, у вас есть два, которые используют диспетчер для интеграции событий файлового дескриптора в цикл событий GUI.Общее описание событийных циклов можно найти в Wikipedia .Конкретное описание Gtk + можно найти в справочнике .

Решение вашей проблемы: используйте функцию g_io_add_watch для интеграции вашего действия в основной цикл событий. Здесь - пример на C. Python должен быть аналогичным.

0 голосов
/ 09 мая 2011

Да, здесь есть 2 вопроса.Во-первых, вам нужно указать тайм-аут чтения, чтобы не блокировать до завершения подпроцесса.Во-вторых, вероятно, что происходит буферизация, которая нежелательна.

Для решения первой проблемы и асинхронного чтения из подпроцесса вы можете попробовать мой модуль подпроцесса с таймаутом: http://www.pixelbeat.org/libs/subProcess.pyОбратите внимание, что это просто, но также старое и только Linux.Он использовался в качестве основы для нового модуля подпроцесса python, поэтому вам лучше воспользоваться этим, если вам нужна переносимость.

Чтобы понять / контролировать любую дополнительную буферизацию, которая может произойти, см .: http://www.pixelbeat.org/programming/stdio_buffering/

...