Python “如何重定向”;stdout";标签小部件?

Python “如何重定向”;stdout";标签小部件?,python,tkinter,label,stdout,Python,Tkinter,Label,Stdout,我正在尝试将stdout重定向到标签小部件。目标是将脚本中的所有Python打印内容“打印”到标签中 但是当我点击按钮1时,什么都没有发生 这是我的密码: from Tkinter import * import sys import tkMessageBox class App: def __init__(self, master): self.frame = Frame(master, borderwidth=5, relief=RIDGE)

我正在尝试将stdout重定向到标签小部件。目标是将脚本中的所有Python打印内容“打印”到标签中

但是当我点击
按钮1
时,什么都没有发生

这是我的密码:

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

无法看到文本集的原因是,它在一瞬间设置正确,然后立即设置为空白。这是因为print在print语句之后向stdout发送新行。下面是一个修改后的版本,它附加到标签上,而不是覆盖每个打印语句

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

我创建了一个类,它将stdout write调用复制到tkinter小部件,无论是标签还是文本。在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:我收到了反对票,所以这是最新的。我在标签小部件中使用它,print()函数在我的小部件中平滑显示。此外,作为一个额外的特性,如果我不向write调用传递任何参数,比如说-1作为结束参数,那么它就不会显示最后一行(小心索引)。我之所以使用它,是因为我在小部件上附加了一个滑块。我很快就会发布一个演示。

你太棒了!这是完美的工作!谢谢您的帮助,我不知道print总是在print语句之后向stdout发送新行,很高兴知道;-)(我不能投赞成票,因为我的声望不超过15,但一旦我有了它,我会投你的票;)