5

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

但是当我点击BUTTON1什么都没有发生...

这是我的代码:

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

2 回答 2

4

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

    class StdoutRedirector(IORedirector):
        def write(self,str):
           self.TEXT_INFO.config(text=self.TEXT_INFO.cget('text') + str)
于 2012-06-01T08:37:56.167 回答
3

我创建了一个类,它将标准输出写入调用复制到 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:我收到了反对票,所以这是更新的。我在 Label 小部件中使用它,并且 print() 函数在我的小部件中顺利显示。此外,如果我将 None 传递给 write 调用并假设 -1 作为结束参数,作为一个额外的功能,那么它不会显示最后一行(小心索引)。我使用它是因为我在小部件上附加了一个滑块。我将很快发布一个演示。

于 2013-05-09T11:37:49.380 回答