Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to redirect print statements to Tkinter text widget

Tags:

python

tkinter

I have a Python program which performs a set of operations and prints the response on STDOUT. Now I am writing a GUI which will call that already existing code and I want to print the same contents in the GUI instead of STDOUT. I will be using the Text widget for this purpose. I do not want to modify my existing code which does the task (This code is used by some other programs as well).

Can someone please point me to how I can use this existing task definition and use its STDOUT result and insert it into a text widget? In the main GUI program I want to call this task definition and print its results to STDOUT. Is there a way to use this information?

like image 728
sarbjit Avatar asked Sep 10 '12 12:09

sarbjit


People also ask

What is use of the Mainloop () in Tkinter?

mainloop() tells Python to run the Tkinter event loop. This method listens for events, such as button clicks or keypresses, and blocks any code that comes after it from running until you close the window where you called the method.

What does get () do in Tkinter?

An Entry widget in Tkinter is nothing but an input widget that accepts single-line user input in a text field. To return the data entered in an Entry widget, we have to use the get() method. It returns the data of the entry widget which further can be printed on the console.

What is Tk () in Tkinter Python?

Tkinter is a Python package which comes with many functions and methods that can be used to create an application. In order to create a tkinter application, we generally create an instance of tkinter frame, i.e., Tk(). It helps to display the root window and manages all the other components of the tkinter application.


2 Answers

You can probably solve this by replacing sys.stdout with your own file-like object that writes to the text widget.

For example:

import Tkinter as tk
import sys

class ExampleApp(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        toolbar = tk.Frame(self)
        toolbar.pack(side="top", fill="x")
        b1 = tk.Button(self, text="print to stdout", command=self.print_stdout)
        b2 = tk.Button(self, text="print to stderr", command=self.print_stderr)
        b1.pack(in_=toolbar, side="left")
        b2.pack(in_=toolbar, side="left")
        self.text = tk.Text(self, wrap="word")
        self.text.pack(side="top", fill="both", expand=True)
        self.text.tag_configure("stderr", foreground="#b22222")

        sys.stdout = TextRedirector(self.text, "stdout")
        sys.stderr = TextRedirector(self.text, "stderr")

    def print_stdout(self):
        '''Illustrate that using 'print' writes to stdout'''
        print "this is stdout"

    def print_stderr(self):
        '''Illustrate that we can write directly to stderr'''
        sys.stderr.write("this is stderr\n")

class TextRedirector(object):
    def __init__(self, widget, tag="stdout"):
        self.widget = widget
        self.tag = tag

    def write(self, str):
        self.widget.configure(state="normal")
        self.widget.insert("end", str, (self.tag,))
        self.widget.configure(state="disabled")

app = ExampleApp()
app.mainloop()
like image 61
Bryan Oakley Avatar answered Sep 17 '22 09:09

Bryan Oakley


In python, whenever you call print('examplestring'), you're indirectly calling sys.stdout.write('examplestring') :

from tkinter import *
root=Tk()
textbox=Text(root)
textbox.pack()
button1=Button(root, text='output', command=lambda : print('printing to GUI'))
button1.pack()

Method 1: Print out on GUI

def redirector(inputStr):
    textbox.insert(INSERT, inputStr)

sys.stdout.write = redirector #whenever sys.stdout.write is called, redirector is called.

root.mainloop()

Infact we're calling print -(callsfor)-> sys.stdout.write -(callsfor)-> redirector

Method 2: Writing a decorator - print out on both CLI and GUI

def decorator(func):
    def inner(inputStr):
        try:
            textbox.insert(INSERT, inputStr)
            return func(inputStr)
        except:
            return func(inputStr)
    return inner

sys.stdout.write=decorator(sys.stdout.write)
#print=decorator(print)  #you can actually write this but not recommended

root.mainloop()

What a decorator does is it actually assign the func sys.stdout.write to func inner

sys.stdout.write=inner

and func inner adds an extra line of code before calling back the actual sys.stdout.write

This is in a way updating the older func sys.stdout.write to have new feature. You will notice that I used a try-except such that if there's any error in printing to the textbox, I would at least retain the original func of sys.stdout.write to the CLI

Method 3: Bryan Oakley's example

...
    sys.stdout = TextRedirector(self.text, "stdout")
...
class TextRedirector(object):
    def __init__(self, widget, tag="stdout"):
        self.widget = widget
        self.tag = tag

    def write(self, str):
        self.widget.configure(state="normal")
        self.widget.insert("end", str, (self.tag,))
        self.widget.configure(state="disabled")

What he did was that he assigned sys.stdout to Class TextRedirector with a Method .write(str)

so calling print('string') -calls for-> sys.stdout.write('string') -callsfor-> TextRedirector.write('string')

like image 26
Yuukio Avatar answered Sep 21 '22 09:09

Yuukio