2016-04-13 32 views
2

Bir işlevin stdout'unu daha titiz bir metin widget'ına yeniden yönlendirmeye çalışıyorum. Çalıştığım sorun, her satırı tek tek listelemek yerine her pencereyi yeni bir pencereye yazmasıdır. İşlev, bir dizini tarar ve 0k olan herhangi bir dosyayı listeler. Hiçbir dosya 0k değilse, bunu yazdırır. Yani, bir dizinde 30 0k dosyaları varsa, her birinde tek bir satır ile 30 pencere açacaktır sorun olur. Şimdi sorunun ne olduğunu biliyorum. Benim fonksiyon kodunda bakarsak Zerok() bunu söylüyorum:Metin nesnesini kırpmak için stdout'u yeniden yönlendirin

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

Her zaman os.stat o zaman o yönlendiricisi gönderiyor 0k bir dosyayı gördüğünü biliyoruz, işte bu yüzden her biri için onun yeni bir pencere dosya. Sadece nasıl düzelteceğimi bilmiyorum. Aşağıdaki kodun tamamı. Yardım için teşekkürler.

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

cevap

1

Düzeltme işlemi basittir: Birden çok yeniden yönlendirici oluşturmayın. Yeniden yönlendiricinin bütün noktası, bir kez oluşturmanız ve normal yazdırma ifadelerinin bu pencerede görünmesidir.

redirector işlevinizde birkaç küçük değişiklik yapmanız gerekir. İlk olarak, Tk'u aramamalı; bunun yerine, bir tkinter programının tam olarak bir kök penceresine sahip olması gerektiğinden, Toplevel örneğini oluşturmalıdır. İkincisi, bir metin gerecini IORedirector'a iletmeniz gerekir, çünkü tam olarak yazılacak widget'ı bilmesi gerekir.

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

Daha sonra, bu işlevi yalnızca bir kez çağırmalısınız. Bundan sonra, pencerede veri görünmesi için normal bir print ifadesi kullanacaksınız.

Sen kodun temel bloğuna oluşturabilirsiniz: o metin aletinin yazma gerektiğinden

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

Sonraki, sen write işlevini değiştirmek gerekir:

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

Son olarak,

def Zerok(): ... Eğer os.stat varsa (Dosya adı) .st_size == 0:
baskı (dosya adı) başka : baskı ("o Directory'de boş dosya yok") kırılma

+0

Teşekkürler Bryan, bunun bir anlamı var ama birkaç noktada kayboldum. – dennis

+0

Teşekkürler @Bryan Oakley, Ben python için süper yeni ve Tkinter daha yeni, bu yüzden yardım ve sabır takdir edilir. Bunun çoğu mantıklı ama birkaç noktada kayboldum. Öncelikle, "Bir metin gerecini IORedirector'a iletmelisiniz ..." Orada kayboldum, açıklayabilir misiniz? İkincisi, bu işlevi tek bir kez ve r = redirector() çağırıyor. Bunun nasıl çalıştığını ve kullanılmadığını mı anlamadım? – dennis

+0

@Dennis: Yanıtımı orijinal olarak eklemeyi unuttuğum bir parça ekledim - 'write' yönteminin metin dosyasına yazma işlevini kullanması gerekiyor. Bir metin widget'ını geçerken - tüm nokta yeniden yönlendiricinin bir şeye yönlendirmesidir. Bu _something_'in ne olduğunu söylemelisin. Bu durumda metin parçacığına yönlendirilmesini istiyorsunuz. –

1

yukarıdaki çözüm çok tamamlandığında; Aslında sadece bir küçük değişiklikle koduma kopyalayıp yapıştırabildim. neden tamamen emin değilim, ancak StdoutRedirector bir yıkama yöntemi gerektirir.

Sanırım, sys.stdout çıktığı zaman bir flush() yöntemini çağırdığı için, ancak bunun ne anlama geldiğini anlamak için yeterince derin olmayan belgelere sığdırılmadığı için.

Yukarıdaki kodu Jupyter ortamında çalıştırmak, kodun yeniden başlatılıncaya kadar kodun süresiz olarak askıda kalmasına neden oldu.Konsol aşağıdaki hataları başladı:

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

basit bir çözüm floş yöntemi ekleyerek StdoutRedirector sınıfa küçük bir değişiklik yapmaktır.

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 

Benden önce gelen devler sayesinde çok net bir açıklama yaptı.

İlgili konular