如何从子进程stdout获取结果并在TextCtrl中实时显示它们? (Python 2.7 - wxPython)

时间:2017-07-24 20:40:24

标签: python-2.7 subprocess wxpython

我正在使用wxPython创建一个GUI。我试图从subprocess.Popen到TextCtrl一次显示一行结果。由于存在大量信息,因此窗口在完全显示所有内容之前经历了一个不响应的阶段。我也在使用线程。 我已经尝试了poll,read(),readline(),itr,并且在窗口的简短NOT RESPONDING阶段之后,输出仍会一次显示而不是逐行显示。如果有人可以帮我解决这个问题,那就太棒了。谢谢!

1 个答案:

答案 0 :(得分:0)

如果你在一个线程中运行subprocess,那么你只需要将对文本控件的引用传递给该线程,然后使用wxPython的线程安全之一调用文本控件的write方法。方法,例如wx.CallAfter。这是一个相当简单的例子:

import subprocess
import time
import wx

from threading import Thread


class PingThread(Thread):

    def __init__(self, text_ctrl):
        Thread.__init__(self)
        self.text_ctrl = text_ctrl
        self.sentinel = True
        self.start()

    def run(self):            
        proc = subprocess.Popen("ping www.google.com",
                                     shell=True,
                                     stdout=subprocess.PIPE)
        while self.sentinel:
            line = proc.stdout.readline()
            if line.strip() == "":
                pass
            else:
                wx.CallAfter(self.text_ctrl.write, line)

            if not line: break

        proc.kill()


class MyFrame(wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self, None, title='Redirecter')
        self.ping_thread = None

        main_sizer = wx.BoxSizer(wx.VERTICAL)

        panel = wx.Panel(self)

        self.log = wx.TextCtrl(panel, style=wx.TE_MULTILINE)

        ping_btn = wx.Button(panel, label='Ping')
        ping_btn.Bind(wx.EVT_BUTTON, self.on_ping)

        main_sizer.Add(self.log, 1, wx.ALL|wx.EXPAND, 5)
        main_sizer.Add(ping_btn, 0, wx.ALL, 5)
        panel.SetSizer(main_sizer)

        self.Bind(wx.EVT_CLOSE, self.on_close)

        self.Show()

    def on_ping(self, event):
        self.ping_thread = PingThread(self.log)

    def on_close(self, event):
        if self.ping_thread:
            self.ping_thread.sentinel = False
            self.ping_thread.join()
        self.Destroy()


if __name__ == '__main__':
    app = wx.App(False)
    frame = MyFrame()
    app.MainLoop()

您可以在以下链接中阅读有关wxPython和线程的更多信息: