Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
657 views
in Technique[技术] by (71.8m points)

python - redirect stdout to tkinter text widget

I'm trying to redirect the stdout of a function to a tkinter text widget. The problem I am running into is that it writes each line to a new window instead of listing everything in one. The function scans a directory and lists any file that is 0k. If no files are 0k it prints that. So, the problem is that if there are 30 0k files in a directory, it will open 30 windows with a single line in each. Now, I know what the problem is. If you look in my function code Zerok() I am telling it:

if os.stat(filename).st_size==0:  
       redirector(filename)

I know that every time os.stat sees a file that is 0k it is then sending that to redirector, that's why its a new window for each file. I just have no idea how to fix it. Complete code below. Thanks for the help.

import Tkinter
from Tkinter import *
import tkFileDialog

class IORedirector(object):
    '''A general class for redirecting I/O to this Text widget.'''
    def __init__(self,text_area):
        self.text_area = text_area

class StdoutRedirector(IORedirector):
    '''A class for redirecting stdout to this Text widget.'''
    def write(self,str):
        self.text_area.write(str,False)

def redirector(inputStr):
    import sys
    root = Tk()
    sys.stdout = StdoutRedirector(root)
    T = Text(root)
    T.pack()
    T.insert(END, inputStr)

####This Function checks a User defined directory for 0k files
def Zerok():
    import os
    sys.stdout.write = redirector #whenever sys.stdout.write is called, redirector is called.
    PATH = tkFileDialog.askdirectory(initialdir="/",title='Please select a directory')  
    for root,dirs,files in os.walk(PATH):  
     for name in files:  
      filename=os.path.join(root,name)  
      if os.stat(filename).st_size==0:  
       redirector(filename)
      else:
          redirector("There are no empty files in that Directory")
          break

#############################Main GUI Window###########################
win = Tk()
f = Frame(win)
b1 = Button(f,text="List Size")
b2 = Button(f,text="ZeroK")
b3 = Button(f,text="Rename")
b4 = Button(f,text="ListGen")
b5 = Button(f,text="ListDir")
b1.pack()
b2.pack()
b3.pack()
b4.pack()
b5.pack()
l = Label(win, text="Select an Option")
l.pack()
f.pack()
b2.configure(command=Zerok)
win.mainloop()
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The above solution is very complete; I was able to essentially copy and paste it into my code with only one small modification. I'm not entirely sure why, but the StdoutRedirector requires a flush method.

I'm guessing it's because sys.stdout calls a flush() method when it exits, but I'm haven't waded into the docs deep enough to actually understand what that means.

Running the above code in the Jupyter environment caused the code to hang indefinitely until the kernel was restarted. The console kicks the following errors:

sys.stdout.flush()
AttributeError: 'StdoutRedirector' object has no attribute 'flush'
ERROR:tornado.general:Uncaught exception, closing connection.

The simple solution is to make a small change to the StdoutRedirector class by adding a flush method.

class StdoutRedirector(IORedirector):
    '''A class for redirecting stdout to this Text widget.'''

    def write(self,str):
        self.text_area.insert("end", str)
    def flush(self):
        pass

Thanks to the giants that came before me and offered this very clear explanation.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...