如何将打印语句重定向到 Tkinter 文本小部件

新手上路,请多包涵

我有一个 Python 程序,它执行一组操作并在 STDOUT 上打印响应。现在我正在编写一个 GUI,它将调用已经存在的代码,我想在 GUI 而不是 STDOUT 中打印相同的内容。为此,我将使用文本小部件。我不想修改执行任务的现有代码(此代码也被其他一些程序使用)。

有人可以告诉我如何使用这个现有的任务定义并使用它的 STDOUT 结果并将其插入文本小部件吗?在主 GUI 程序中,我想调用此任务定义并将其结果打印到 STDOUT。有没有办法使用这些信息?

原文由 sarbjit 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 915
2 个回答

您可以通过将 sys.stdout 替换为您自己的写入文本小部件的类文件对象来解决此问题。

例如:

 import Tkinter as tk
import sys

class ExampleApp(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        toolbar = tk.Frame(self)
        toolbar.pack(side="top", fill="x")
        b1 = tk.Button(self, text="print to stdout", command=self.print_stdout)
        b2 = tk.Button(self, text="print to stderr", command=self.print_stderr)
        b1.pack(in_=toolbar, side="left")
        b2.pack(in_=toolbar, side="left")
        self.text = tk.Text(self, wrap="word")
        self.text.pack(side="top", fill="both", expand=True)
        self.text.tag_configure("stderr", foreground="#b22222")

        sys.stdout = TextRedirector(self.text, "stdout")
        sys.stderr = TextRedirector(self.text, "stderr")

    def print_stdout(self):
        '''Illustrate that using 'print' writes to stdout'''
        print "this is stdout"

    def print_stderr(self):
        '''Illustrate that we can write directly to stderr'''
        sys.stderr.write("this is stderr\n")

class TextRedirector(object):
    def __init__(self, widget, tag="stdout"):
        self.widget = widget
        self.tag = tag

    def write(self, str):
        self.widget.configure(state="normal")
        self.widget.insert("end", str, (self.tag,))
        self.widget.configure(state="disabled")

app = ExampleApp()
app.mainloop()

原文由 Bryan Oakley 发布,翻译遵循 CC BY-SA 3.0 许可协议

在 python 中,无论何时调用 print(‘examplestring’),都在间接调用 sys.stdout.write(‘examplestring’):

 from tkinter import *
root=Tk()
textbox=Text(root)
textbox.pack()
button1=Button(root, text='output', command=lambda : print('printing to GUI'))
button1.pack()

方法 1:在 GUI 上打印出来

def redirector(inputStr):
    textbox.insert(INSERT, inputStr)

sys.stdout.write = redirector #whenever sys.stdout.write is called, redirector is called.

root.mainloop()

事实上我们正在调用 print -(callsfor)-> sys.stdout.write -(callsfor)-> redirector

方法 2:编写装饰器 - 在 CLI 和 GUI 上打印出来

def decorator(func):
    def inner(inputStr):
        try:
            textbox.insert(INSERT, inputStr)
            return func(inputStr)
        except:
            return func(inputStr)
    return inner

sys.stdout.write=decorator(sys.stdout.write)
#print=decorator(print)  #you can actually write this but not recommended

root.mainloop()

装饰器所做的实际上是将 func sys.stdout.write 分配给 func inner

 sys.stdout.write=inner

并且 func inner 在回调实际的 sys.stdout.write 之前添加了一行额外的代码

这在某种程度上更新了旧的 func sys.stdout.write 以具有新功能。您会注意到我使用了 try-except 这样如果在打印到文本框时出现任何错误,我至少会保留 sys.stdout.write 的原始功能到 CLI

方法 3:Bryan Oakley 的例子

...
    sys.stdout = TextRedirector(self.text, "stdout")
...
class TextRedirector(object):
    def __init__(self, widget, tag="stdout"):
        self.widget = widget
        self.tag = tag

    def write(self, str):
        self.widget.configure(state="normal")
        self.widget.insert("end", str, (self.tag,))
        self.widget.configure(state="disabled")

他所做的是,他使用方法 .write(str) 将 sys.stdout 分配给 Class TextRedirector

所以调用 print(‘string’) -calls for-> sys.stdout.write(‘string’) -callsfor-> TextRedirector.write(‘string’)

原文由 Yuukio 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题