2012-06-01 13 views
5

Próbuję przekierować standardowe wyjście do widgetu Label. Celem jest "wydrukowanie" na etykiecie wszystkich wydruków Pythona znajdujących się w moim skrypcie.Jak przekierować "stdout" do widgetu Label?

Ale gdy klikam na BUTTON1 nic się nie dzieje ...

Oto mój kod:

from Tkinter import * 
import sys 
import tkMessageBox 


class App: 

    def __init__(self, master): 

     self.frame = Frame(master, borderwidth=5, relief=RIDGE) 
     self.frame.grid() 

     class IORedirector(object): 
      def __init__(self,TEXT_INFO): 
       self.TEXT_INFO = TEXT_INFO 

     class StdoutRedirector(IORedirector): 
      def write(self,str): 
       self.TEXT_INFO.config(text=str) 

     self.TEXT_HEADER = self.text_intro = Label(self.frame, bg="lightblue",text="MY SUPER PROGRAMM") ## HEADER TEXT 
     self.TEXT_HEADER.grid(row=0, column=0, columnspan=2, sticky=W+E+N+S) 

     self.MENU = Frame(self.frame, borderwidth=5, relief=RIDGE, height=12) 

     self.MENU.grid(row=1, column=0, sticky=N) 

     self.button = Button(self.MENU, text="QUIT", fg="red", bg="red", command=self.frame.quit) 
     self.button.grid(row=4, column=0) 

     self.BUTTON1 = Button(self.MENU, text="BUTTON1", command=self.BUTTON1_CMD) 
     self.BUTTON1.grid(row=0, column=0,sticky=W+E) 

     self.TEXT_INFO = Label(self.frame, height=12, width=40, text="I WANT TO SEE THE STDOUT OUTPUT HERE", bg="grey",borderwidth=5, relief=RIDGE) 
     self.TEXT_INFO.grid(row=1, column=1) 

     sys.stdout = StdoutRedirector(self.TEXT_INFO) 

    def BUTTON1_CMD(self): 
     print "TEST NUMBER ONE" 
     print "TEST NUMBER TWO" 


root = Tk() 
app = App(root) 
root.mainloop() 

Odpowiedz

4

Powodem nie widzisz zestawu tekstu jest to, że jest prawidłowo ustawiony na ułamek sekundy a następnie natychmiast ustawić jako puste. Dzieje się tak dlatego, że print wysyła znak nowej linii na standardowe wyjście po poleceniach print. Oto zmodyfikowana wersja, która dołącza do etykiety, a nie zastępuje ją dla każdego polecenia drukowania.

class StdoutRedirector(IORedirector): 
     def write(self,str): 
      self.TEXT_INFO.config(text=self.TEXT_INFO.cget('text') + str) 
+1

Jesteś niesamowity! Działa to doskonale! Dziękuję za pomoc, nie wiedziałem, że wydruk zawsze wysyła nowy znak do stdout po oświadczeniu wydruku, dobrze wiedzieć ;-) (Nie mogę głosować w górę, ponieważ nie mam więcej niż 15 punktów reputacji, ale jak tylko to będę mieć, zagłosuję na ciebie;)) –

3

zrobiłem klasa których kopie zapisu stdout wzywa do widgetu tkinter być ona etykietę lub tekstu. Pracuje dla mnie na Python3.3.1/WindowsXP .:

import sys 

class StdoutToWidget: 
    ''' 
    Retrieves sys.stdout and show write calls also in a tkinter 
    widget. It accepts widgets which have a "text" config and defines 
    their width and height in characters. It also accepts Text widgets. 
    Use stop() to stop retrieving. 

    You can manage output height by using the keyword argument. By default 
    the class tries to get widget\'s height configuration and use that. If 
    that fails it sets self.height to None which you can also do manually. 
    In this case the output will not be trimmed. However if you do not 
    manage your widget, it can grow vertically hard by getting more and 
    more inputs. 
    ''' 

    # Inspired by Jesse Harris and Stathis 
    # http://stackoverflow.com/a/10846997/2334951 
    # http://stackoverflow.com/q/14710529/2334951 

    # TODO: horizontal wrapping 
    #  make it a widget decorator (if possible) 
    #  height management for Text widget mode 

    def __init__(self, widget, height='default', width='default'): 
     self._content = [] 
     self.defstdout = sys.stdout 
     self.widget = widget 

     if height == 'default': 
      try: 
       self.height = widget.cget('height') 
      except: 
       self.height = None 
     else: 
      self.height = height 
     if width == 'default': 
      try: 
       self.width = widget.cget('width') 
      except: 
       self.width = None 
     else: 
      self.width = width 

    def flush(self): 
     ''' 
     Frame sys.stdout's flush method. 
     ''' 
     self.defstdout.flush() 

    def write(self, string, end=None): 
     ''' 
     Frame sys.stdout's write method. This method puts the input 
     strings to the widget. 
     ''' 

     if string is not None: 
      self.defstdout.write(string) 
      try: 
       last_line_last_char = self._content[-1][-1] 
      except IndexError: 
       last_line_last_char = '\n' 
      else: 
       if last_line_last_char == '\n': 
        self._content[-1] = self._content[-1][:-1] 

      if last_line_last_char != '\n' and string.startswith('\r'): 
       self._content[-1] = string[1:] 
      elif last_line_last_char != '\n': 
       self._content[-1] += string 
      elif last_line_last_char == '\n' and string.startswith('\r'): 
       self._content.append(string[1:]) 
      else: 
       self._content.append(string) 

     if hasattr(self.widget, 'insert') and hasattr(self.widget, 'see'): 
      self._write_to_textwidget() 
     else: 
      self._write_to_regularwidget(end) 

    def _write_to_regularwidget(self, end): 
     if self.height is None: 
      self.widget.config(text='\n'.join(self.content)) 
     else: 
      if not end: 
       content = '\n'.join(self.content[-self.height:]) 
      else: 
       content = '\n'.join(self.content[-self.height+end:end]) 
      self.widget.config(text=content) 

    def _write_to_textwidget(self): 
     self.widget.insert('end', '\n'.join(self.content)) 
     self.widget.see('end')   

    def start(self): 
     ''' 
     Starts retrieving. 
     ''' 
     sys.stdout = self 

    def stop(self): 
     ''' 
     Stops retrieving. 
     ''' 
     sys.stdout = self.defstdout 

    @property 
    def content(self): 
     c = [] 
     for li in self._content: 
      c.extend(li.split('\n')) 

     if not self.width: 
      return c 
     else: 
      result = [] 
      for li in c: 
       while len(li) > self.width: 
        result.append(li[:self.width]) 
        li = li[self.width:] 
       result.append(li) 
      return result 

    @content.setter 
    def content(self, string): 
     self._content = string.split('\n') 

    @property 
    def errors(self): 
     return self.defstdout.errors 

    @property 
    def encoding(self): 
     return self.defstdout.encoding 

Edit1: Otrzymałem downvote, więc tutaj jest aktualizowany jeden. Używam tego w widgecie Label, a funkcje print() pojawiają się płynnie w moim widgecie. Ponadto jako dodatkowa funkcja, jeśli przekażę None do zapisu, a powiedzmy -1 jako argument końcowy, to nie wyświetli ostatniej linii (ostrożnie z indeksowaniem). Używam tego, ponieważ załączam suwak do widżetu. Niedługo opublikuję demo.