Python “如何重定向”;stdout";标签小部件?
我正在尝试将stdout重定向到标签小部件。目标是将脚本中的所有Python打印内容“打印”到标签中 但是当我点击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)
按钮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,但一旦我有了它,我会投你的票;)