wxPython, получая вывод из подпроцесса в режиме реального времени - PullRequest
1 голос
/ 13 июля 2011

Я работаю над приложением в wxPython, которое представляет собой графический интерфейс для утилиты командной строки.В графическом интерфейсе есть текстовый элемент управления, который должен отображать вывод из приложения.Я запускаю команду оболочки с использованием подпроцесса, но не получаю от нее никакого вывода, пока она не завершится.

Я пробовал несколько решений, но ни одно из них, похоже, не работает.Ниже приведен код, который я использую в данный момент (обновлено):

       def onOk(self,event):        
        self.getControl('infotxt').Clear()
        try:
            thread = threading.Thread(target=self.run)
            thread.setDaemon(True)
            thread.start()

        except Exception:
            print 'Error starting thread'    

    def run(self):    
        args = dict()
        # creating a command to execute...

        cmd = ["aplcorr", "-vvfile", args['vvfile'], "-navfile", args['navfile'], "-lev1file", args['lev1file'], "-dem", args['dem'], "-igmfile", args['outfile']]

        proc = subprocess.Popen(' '.join(cmd), shell=True, stdout=subprocess.PIPE, stderr.subprocess.PIPE)         

        print
        while True:
            line = proc.stdout.readline()
            wx.Yield()
            if line.strip() == "":
                pass
            else:                
                print line.strip()                
            if not line: break
        proc.wait()

class RedirectInfoText:
    """ Class to redirect stdout text """
    def __init__(self,wxTextCtrl):
        self.out=wxTextCtrl

    def write(self,string):
        self.out.WriteText(string)

class RedirectErrorText:
    """ Class to redirect stderr text """    
    def __init__(self,wxTextCtrl):
        self.out.SetDefailtStyle(wx.TextAttr())
        self.out=wxTextCtrl

    def write(self,string):
        self.out.SetDefaultStyle(wx.TextAttr(wx.RED))
        self.out.WriteText(string)

В частности, мне понадобится вывод в реальном времени для создания индикатора выполнения.

Изменить: я изменил свой код, основываясь на предложении Майка Дрисколла.Иногда кажется, что это работает, но большую часть времени я получаю одну из следующих ошибок:

(python: 7698): Gtk-CRITICAL **: gtk_text_layout_real_invalidate: утверждение `layout-> wrap_loop_count== 0 'не удалось

или

(python: 7893): Gtk-WARNING **: неверный итератор текстового буфера: либо итератор неинициализирован, либо символы/ pixbufs / widgets в буфере были изменены с момента создания итератора.Вы должны использовать метки, номера символов или номера строк, чтобы сохранить положение между изменениями буфера.Вы можете применять теги и вставлять метки, не делая недействительными ваши итераторы, но любая мутация, которая влияет на содержимое «индексируемого» буфера (содержимое, на которое можно ссылаться смещением символов), сделает недействительными все ожидающие итераторы Ошибка сегментации (дамп ядра)

Есть какие-нибудь подсказки?

Ответы [ 2 ]

2 голосов
/ 14 июля 2011

Проблема заключается в том, что вы пытаетесь выполнить wx.Yield и обновить выходные виджеты из контекста потока, выполняющего процесс, вместо того, чтобы выполнять обновление из потока графического интерфейса.

  1. Поскольку вы запускаете процесс из потока, не должно быть необходимости вызывать wx.Yield, поскольку вы не блокируете поток GUI, и поэтому любые ожидающие события пользовательского интерфейса должны обрабатываться в любом случае в обычном режиме.

  2. Взгляните на класс wx.PyOnDemandOutputWindow для примера того, как обрабатывать распечатки или другие выходные данные, которые исходят из потока без графического интерфейса пользователя.

1 голос
/ 13 июля 2011

Это может быть немного сложно, но я нашел один способ сделать это, о котором я писал здесь: http://www.blog.pythonlibrary.org/2010/06/05/python-running-ping-traceroute-and-more/

После того, как вы настроили перенаправление текста, вам просто нужно сделатькак то так:

def pingIP(self, ip):
    proc = subprocess.Popen("ping %s" % ip, shell=True,
                            stdout=subprocess.PIPE)
    print
    while True:
        line = proc.stdout.readline()
        wx.Yield()
        if line.strip() == "":
            pass
        else:
            print line.strip()
        if not line: break
    proc.wait()

В статье показано, как перенаправить текст тоже.Надеюсь, это поможет!

...