2016-04-13 8 views
2

Ich versuche, die Stdout einer Funktion zu einem tkinter Text Widget umleiten. Das Problem, mit dem ich konfrontiert bin, ist, dass es jede Zeile in ein neues Fenster schreibt, anstatt alles in einem aufzulisten. Die Funktion scannt ein Verzeichnis und listet alle Dateien auf, die 0k sind. Wenn keine Dateien 0k sind, wird das gedruckt. Das Problem besteht also darin, dass bei 30 0k-Dateien in einem Verzeichnis 30 Fenster mit jeweils einer einzelnen Zeile geöffnet werden. Jetzt weiß ich, was das Problem ist. Wenn Sie in meiner Funktion Code aussehen Zerok() ich es sage:redirect stdout zu tkinter Text widget

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

Ich weiß, dass jedes Mal, os.stat eine Datei, die 0k sieht, ist es dann sendet das Redirector, deshalb ist es ein neues Fenster für jeden Datei. Ich habe nur keine Ahnung, wie ich es beheben kann. Kompletter Code unten. Danke für die Hilfe.

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() 

Antwort

1

Die Fehlerbehebung ist einfach: Erstellen Sie nicht mehr als einen Redirector. Der Hauptpunkt des Redirectors ist, dass Sie ihn einmal erstellen, und dann werden normale Druckanweisungen in diesem Fenster angezeigt.

Sie müssen einige kleine Änderungen an Ihrer redirector Funktion vornehmen. Erstens sollte es nicht anrufen Tk; Stattdessen sollte es eine Instanz von Toplevel erstellen, da ein tkinter-Programm genau ein Root-Fenster haben muss. Zweitens müssen Sie ein Text-Widget an IORedirector übergeben, da es das genaue Widget zum Schreiben benötigt.

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

Als nächstes sollten Sie diese Funktion nur ein einziges Mal aufrufen. Von nun an, um Daten in dem Fenster erscheinen zu lassen, würden Sie eine normale print-Anweisung verwenden.

Sie es im Hauptcodeblock erstellen:

win = Tk() 
... 
r = redirector() 
win.mainloop() 

Als nächstes müssen Sie die write Funktion ändern, da es zu dem Text-Widget schreiben müssen:

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

Schließlich Ändern Sie Ihre Zerok Funktion, um Druckanweisungen zu verwenden:

def Zerok(): ... wenn os.stat (Dateiname) .st_size == 0:
print (Dateiname) anderes: print ("Es gibt keine leeren Dateien in diesem Verzeichnis") Pause

+0

Dank Bryan, macht das meiste Sinn, aber ich bin in einigen Punkten verloren. – dennis

+0

Dank @ Bryan Oakley, ich bin super neu zu Python und noch neuer zu Tkinter, so dass Ihre Hilfe und Geduld geschätzt wird. Das meiste macht Sinn, aber ich bin in einigen Punkten verloren. Erstens: "Sie müssen ein Text-Widget an IORedirector übergeben ..." Ich bin dort verloren, können Sie klären? Zweitens, Aufruf dieser Funktion ein einziges Mal und r = Redirector(). Ich verstehe nicht, wie das funktioniert und benutzt wird? – dennis

+0

@Dennis: Ich habe meine Antwort so bearbeitet, dass sie ein Stück enthält, das ich vergessen habe hinzuzufügen - die 'write' Methode muss die Funktion zum Schreiben in die Textdatei verwenden. Was das Übergeben eines Text-Widgets anbelangt - der Umleitungspunkt ist für den Redirector der einzige, der auf etwas umleitet. Sie müssen ihm sagen, was das ist. In diesem Fall möchten Sie es zum Text-Widget umleiten. –

1

Die obige Lösung ist sehr komplett; Ich konnte es mit nur einer kleinen Änderung im Wesentlichen kopieren und in meinen Code einfügen. Ich bin mir nicht ganz sicher warum, aber die StdoutRedirector erfordert eine Flush-Methode.

Ich vermute es ist, weil sys.stdout eine flush() Methode aufruft, wenn es beendet wird, aber ich bin nicht in die Dokumente tief genug gewatet, um wirklich zu verstehen, was das bedeutet.

Das Ausführen des obigen Codes in der Jupyter-Umgebung führte dazu, dass der Code bis zum Neustart des Kernels auf unbestimmte Zeit hängen blieb.Die Konsole schlägt die folgenden Fehler:

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

Die einfache Lösung ist durch Zugabe einer Flush-Methode eine kleine Änderung an die StdoutRedirector Klasse zu machen.

Dank der Riesen, die vor mir kamen und diese sehr klare Erklärung anboten.