Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to redirect stdout to a Tkinter Text widget

My base program imports it's GUI interface from a script GUI.py

old_stdout = sys.stdout

root = Tk.Tk()
root.title('Coursera-dl')
root.geometry("345x230")
app = GUI.Interface(root)
app.mainloop()

if app.button_press() == True and app.return_data():
    data = app.return_data()
    main(data[0],data[1],data[2],data[3],data[4],data[5],data[6],data[7],data[8])

sys.stdout = old_stdout

In my GUI.py :

class Interface(ttk.Frame):
    def __init__(self,parent=None):
        ttk.Frame.__init__(self,parent)
        self.parent = parent
        self.New_Window()

    def New_Window(self):
        self.newWindow = Tk.Toplevel(self.parent)
        self.app = CoreGUI(self.newWindow)


class StdoutRedirector(object):
    def __init__(self,text_widget):
        self.text_space = text_widget

    def write(self,string):
        self.text_space.insert('end', string)
        self.text_space.see('end')


class CoreGUI(object):
    def __init__(self,parent):
        self.parent = parent
        self.InitUI()

    def InitUI(self):
        self.text_box = Tk.Text(self.parent, wrap='word', height = 11, width=50)
        self.text_box.grid(column=0, row=0, columnspan = 2, sticky='NSWE', padx=5, pady=5)
        sys.stdout = StdoutRedirector(self.text_box)

But what It does is it opens two windows and the first window (the toplevel one) works as expected and the second is idle , This is what is expected until I click a certain button which after pressing prints data continuously and the data printed should appear in the second window's text widget however this doesn't happen and there is no response from the program and when I close the Toplevel window an error message appears

"TclError: invalid command name "".33328904.33329104"""

So How can I print the data in Text Widget rather than in the console?


EDIT:

Inorder to help ya'll if you struggling with this, I've made a script to redirect stdout to a Tkinter Text widget, see it in action here :-)

like image 526
K DawG Avatar asked Aug 29 '13 17:08

K DawG


1 Answers

The problem is that when you call app.mainloop(), the thread is busy executing the Tkinter mainloop, so the statements before it are not executed until you exit the loop. But once you exit the mainloop, you try to use the Text widget but it is already destroyed.

I recommend you to move the call to main to the callback of a Tkinter widget (I suppose you are already trying to do that with app.button_press()), so the Text object can be used to display the text.

class CoreGUI(object):
    def __init__(self,parent):
        self.parent = parent
        self.InitUI()
        button = Button(self.parent, text="Start", command=self.main)
        button.grid(column=0, row=1, columnspan=2)

    def main(self):
        print('whatever')

    def InitUI(self):
        self.text_box = Text(self.parent, wrap='word', height = 11, width=50)
        self.text_box.grid(column=0, row=0, columnspan = 2, sticky='NSWE', padx=5, pady=5)
        sys.stdout = StdoutRedirector(self.text_box)


root = Tk()
gui = CoreGUI(root)
root.mainloop()
like image 165
A. Rodas Avatar answered Oct 29 '22 12:10

A. Rodas