Tkinter – Redirecting stdout / stderr

Redirecting stdout seems to be a pretty common request on the wxPython users group, so I decided to see how easy it would be to do it with Tkinter. The typical use case for redirecting stdout or stderr is that you are calling some other process (like ping or tracert) and you want to catch what it’s doing to put it into your UI. Usually you can just use Python’s subprocess module and call its communicate() method to access the data. Then you can just print it to stdout and it will magically appear in your UI’s widget of choice.

Our finished user interface will look something like the following:

tkredirect.png

Let’s find out how to do this with Tkinter:

import ScrolledText
import sys
import tkFileDialog
import Tkinter


########################################################################
class RedirectText(object):
    """"""

    #----------------------------------------------------------------------
    def __init__(self, text_ctrl):
        """Constructor"""
        self.output = text_ctrl
        
    #----------------------------------------------------------------------
    def write(self, string):
        """"""
        self.output.insert(Tkinter.END, string)
    

########################################################################
class MyApp(object):
    """"""

    #----------------------------------------------------------------------
    def __init__(self, parent):
        """Constructor"""
        self.root = parent
        self.root.title("Redirect")
        self.frame = Tkinter.Frame(parent)
        self.frame.pack()
        
        self.text = ScrolledText.ScrolledText(self.frame)
        self.text.pack()
        
        # redirect stdout
        redir = RedirectText(self.text)
        sys.stdout = redir
        
        btn = Tkinter.Button(self.frame, text="Open file", command=self.open_file)
        btn.pack()
        
    #----------------------------------------------------------------------
    def open_file(self):
        """
        Open a file, read it line-by-line and print out each line to
        the text control widget
        """
        options = {}
        options['defaultextension'] = '.txt'
        options['filetypes'] = [('all files', '.*'), ('text files', '.txt')]
        options['initialdir'] = '/home'
        options['parent'] = self.root
        options['title'] = "Open a file"
        
        with tkFileDialog.askopenfile(mode='r', **options) as f_handle:
            for line in f_handle:
                print line
                
#----------------------------------------------------------------------
if __name__ == "__main__":
    root = Tkinter.Tk()
    root.geometry("800x600")
    app = MyApp(root)
    root.mainloop()

That was a fair bit of code. Let’s take a minute or two to break it down. First off, we imported ScrolledText, which is text control that includes a scroll bar. We also imported tkFileDialog which gives us the ability to open a file. To make this example really simple, we will just use the dialog to open a text file and print it out line-by-line to stdout.

The first class we see is called RedirectText. It takes a text control widget as its parameter. we create a write method that will append a string to the widget’s current value. Then in the MyApp class, we create all the necessary widgets and redirect stdout to our RedirectText class. We also bind the button to our open_file method. This is where the action happens!

Here we create the file dialog and open a file. Then we read the file line by line and print it to stdout. If you try the example, you will see each line of text appear in the ScrolledText widget.


Wrapping Up

As you can see, redirecting stdout / stderr is pretty easy. I hope you will find many neat uses for this technique. Happy coding!


Related Reading

7 thoughts on “Tkinter – Redirecting stdout / stderr”

  1. Will this work if you’re writing to stdout from a different thread? I think it will be problematic then because the other thread will be manipulating the gui, which is usually preserved for the main thread is it not?

  2. You are correct. This example is NOT thread-safe.You would have to do some additional research to find out what Tkinter’s thread-safe methods are.

  3. I’ve tried lots of different solutions I found online, and this one is the easiest to implement in my simple program. Thank you, works beautifully!

Comments are closed.