New programmers start using Python and wxPython each week. So it follows that every few months, I see people asking how to redirect stdout to a wx.TextCtrl on comp.lang.python or the wxPython mailing list. Since this is such a common question, I thought I would write an article about it. Regular readers will know that I have mentioned this concept before in a previous post.
class RedirectText(object): def __init__(self,aWxTextCtrl): self.out=aWxTextCtrl def write(self,string): self.out.WriteText(string)
Note that there’s only one method in this class. It allows us to write the text from stdout or stderr to the text control. It should be noted that the write method is not thread-safe. If you want to redirect text from threads, then change the write statement like this:
def write(self, string): wx.CallAfter(self.out.WriteText, string)
Now let’s dig into the wxPython code we’ll need:
import sys import wx class MyForm(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, wx.ID_ANY, "wxPython Redirect Tutorial") # Add a panel so it looks the correct on all platforms panel = wx.Panel(self, wx.ID_ANY) log = wx.TextCtrl(panel, wx.ID_ANY, size=(300,100), style = wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL) btn = wx.Button(panel, wx.ID_ANY, 'Push me!') self.Bind(wx.EVT_BUTTON, self.onButton, btn) # Add widgets to a sizer sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(log, 1, wx.ALL|wx.EXPAND, 5) sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5) panel.SetSizer(sizer) # redirect text here redir=RedirectText(log) sys.stdout=redir def onButton(self, event): print "You pressed the button!" # Run the program if __name__ == "__main__": app = wx.PySimpleApp() frame = MyForm().Show() app.MainLoop()
In the code above, I create a read-only multi-line text control and a button whose sole purpose is to print some text to stdout. I add them to a BoxSizer to keep the widgets from stacking on top of each other and to better handle resizing of the frame. Next I instantiate the RedirectText class by passing it an instance of my text control. Finally, I set stdout to the RediectText instance, redir (i.e. sys.stdout=redir).
If you want to redirect stderr as well, then just add the following right after “sys.stdout=redir”: sys.stderr=redir
And that’s all there really is to it. Improvements could be made to this, namely color coding (or pre-pending) which messages are from stdout and which are from stderr, but I’ll leave that as an exercise for the reader.
Download the Source