Search code examples
pythonpython-3.xwxpython

Redirect sys.stdout from ping results to a wx.TextCtrl widget


I'm trying to redirect the sys.stdout stream to a wx.TextCtrl widget. In this code, i used ping but how to redirect results to wx.textctrl or statictext widgets. I can send variable from my input to wx.statictext but not able to get the stdout from ping results. hope someone here can help.

I'm using python 3.6.0 with wx 2.8.12.1

import wx
import os


class RandomPanel(wx.Panel):

    def __init__(self, parent, color):

        wx.Panel.__init__(self, parent)
        self.SetBackgroundColour(color)



class MainPanel(wx.Panel):

    def __init__(self, parent):

        wx.Panel.__init__(self, parent)

        topSplitter = wx.SplitterWindow(self)
        vSplitter = wx.SplitterWindow(topSplitter)

        panelOne = RandomPanel(vSplitter, "white")


        self.txt = wx.TextCtrl(panelOne, 
                    style=wx.TE_PROCESS_ENTER, 
                    pos=(7, 8), size=(330, 30))
        self.txt.SetFocus()
        self.txt.Bind(wx.EVT_TEXT_ENTER, self.ping)

        panelTwo = RandomPanel(vSplitter, "white")
        vSplitter.SplitVertically(panelOne, panelTwo)
        vSplitter.SetSashGravity(0.5)

        panelThree = RandomPanel(topSplitter, "black")
        topSplitter.SplitHorizontally(vSplitter, panelThree)
        topSplitter.SetSashGravity(0.5)
        self.term = wx.StaticText(panelThree, -1, '', pos=(6, 100))
        self.term.SetForegroundColour((255, 255, 255))  #set font color
        self.term.SetBackgroundColour((0, 0, 0)) #set background color

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(topSplitter, 1, wx.EXPAND)
        self.SetSizer(sizer)

    def ping(self, event):
        put = self.txt.GetValue()
        self.p = os.system("ping -n 1 "+put)
        self.term.SetLabel(put)
        self.p.AppendText('>>> ')
        self.p.AppendText(event)



class MainFrame(wx.Frame):

    def __init__(self):
           wx.Frame.__init__(self, None, title="ping tool",
                          size=(800, 600))
        panel = MainPanel(self)
        self.Show()



if __name__ == "__main__":
    app = wx.App(False)
    frame = MainFrame()
    app.MainLoop()

Solution

  • Replace import os with from subprocess import call, Popen, PIPE, STDOUT Then replace

    self.p = os.system("ping -n 1 "+put)
    self.term.SetLabel(put)
    self.p.AppendText('>>> ')
    self.p.AppendText(event)
    

    with

    comm = Popen(['ping',put],stdout=PIPE,stderr=STDOUT,universal_newlines=True)
    for i in iter(comm.stdout.readline, b''):
        if i != '': pass
        else: break
        self.term.SetLabel(str(i))
        wx.Yield()
    

    This will read the output from the ping command, output it and then call Yield to allow the wx.App() mainloop to update the screen from within the for loop

    You will probably want to put a stop mechanism in there at some point.

    Edit: To create a set of rolling results, I would change self.term from a StaticText to a TextCtrl

    self.term = wx.TextCtrl(panelThree, -1, '',size=(400,200),style=wx.TE_MULTILINE)
    

    and then in the ping routine change SetLabel to AppendText

    def ping(self, event):
        put = self.txt.GetValue()
        comm = Popen(['ping',put],stdout=PIPE,stderr=STDOUT,universal_newlines=True)
        for i in iter(comm.stdout.readline, b''):
            if i != '': pass
            else: break
            self.term.AppendText(str(i))
            wx.Yield()