Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何将打印语句重定向到Tkinter文本小部件_Python_Tkinter - Fatal编程技术网

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

Python 如何将打印语句重定向到Tkinter文本小部件,python,tkinter,Python,Tkinter,我有一个Python程序,它执行一组操作并在STDOUT上打印响应。现在我正在编写一个GUI,它将调用已经存在的代码,我希望在GUI中打印相同的内容,而不是标准输出。为此,我将使用文本小部件。我不想修改执行此任务的现有代码(此代码也被其他一些程序使用) 有人能告诉我如何使用这个现有的任务定义,使用它的STDOUT结果并将其插入到文本小部件中吗?在主GUI程序中,我想调用此任务定义并将其结果打印到STDOUT。有什么方法可以使用这些信息吗?通常打印到标准输出的函数应该将文本放入文本小部件。通常打印

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


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

通常打印到标准输出的函数应该将文本放入文本小部件。

通常打印到标准输出的函数应该将文本放入文本小部件。

您可能可以通过用自己的类似文件的对象替换
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()

您可能可以通过使用您自己的类似文件的对象替换
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()

您可以使用调用CLI程序,获取它生成的标准输出,并在文本小部件中显示它

类似于(未经测试的):


请注意,这将一直阻止,直到CLI程序完成执行,从而冻结GUI。要绕过阻塞,您可以将此代码放入一个脚本中,并在等待线程完成时让GUI更新。

您可以使用调用CLI程序,获取它生成的标准输出,并在文本小部件中显示它

类似于(未经测试的):


请注意,这将一直阻止,直到CLI程序完成执行,从而冻结GUI。为了避免阻塞,您可以将此代码放入一个脚本中,并在等待线程完成时让GUI更新。

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

方法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)->重定向器

方法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 internal

sys.stdout.write=inner
func inner在调用实际的sys.stdout.write之前添加一行额外的代码

这在某种程度上是更新旧的func sys.stdout.write以具有新功能。 您会注意到,我使用了try,但如果在打印到文本框时出现任何错误,我至少会保留sys.stdout.write的原始func到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")
他所做的是用一个方法将sys.stdout分配给类textdirector.write(str)

这么叫
print('string')-调用->sys.stdout.write('string')-调用->textdirector.write('string')

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

方法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)->重定向器

方法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 internal

sys.stdout.write=inner
func inner在调用实际的sys.stdout.write之前添加一行额外的代码

这在某种程度上是更新旧的func sys.stdout.write以具有新功能。 您会注意到,我使用了try,但如果在打印到文本框时出现任何错误,我至少会保留sys.stdout.write的原始func到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")
他所做的是用一个方法将sys.stdout分配给类textdirector.write(str)

这么叫
print('string')-调用->sys.stdout.write('string')-调用->textdirector.write('string')

事实上,我认为这个问题不限于
tkinter
。任何框架都可以应用,因为它实际上是重定向
sys.stdout

为此,我创建了一个类(
RedirectStdMsg

tl;博士

测试用例 这是
test\u tk\u have\u stop\u btn():

事实上,我认为这个问题不仅限于
tkinter
。任何框架都可以应用,因为它实际上是重定向
sys.stdout

为此,我创建了一个类(
RedirectStdMsg

tl;博士

测试用例 这是
test\u tk\u have\u stop\u btn():

问题在于原始函数的编码方式是,它执行一些操作序列并打印结果(在该函数中,打印命令用于显示状态)。此函数在其他几个程序中共享(所有程序都是基于命令行的函数)。所以我在想是否有办法在主GUI程序中解决这个问题。问题是原始函数的编码方式是它执行一些操作序列并打印结果(在该函数中,print命令用于显示状态)。此函数在其他几个程序中共享(所有程序都是基于命令行的函数)。所以我在想是否有办法在主GUI程序本身中解决这个问题。请您介绍一下“类似文件”的对象。非常感谢您的帮助。我在GUI模块中包含了这个TextRedirector类,并配置为使用标准输出。它解决了我的问题。只有一个问题:我如何停止重定向到stdout。函数调用结束后,我尝试了“sys.stdout=sys.\uu stdout\uuu”。然后,当我尝试打印语句时,控制台(或文本小部件)中看不到输出。我将stdout的原始引用保留为“old_stdout=sys.stdout”,然后将其引用修改为重定向类,然后在函数调用结束后将其还原回old_stdout,
def test_tk_without_stop_btn():
    app = ExampleApp()
    with RedirectStdMsg(sys.stdout)(TextRedirector(app.text, "stdout").write), \
            RedirectStdMsg(sys.stderr)(TextRedirector(app.text, "stderr").write):
        app.mainloop()


def test_tk_have_stop_btn():
    director_out = RedirectStdMsg(sys.stdout)
    director_err = RedirectStdMsg(sys.stderr)
    app = ExampleApp(stdout=director_out, stderr=director_err)
    app.mainloop()


def test_to_file():

    # stdout test
    with open('temp.stdout.log', 'w') as file_obj:
        with RedirectStdMsg(sys.stdout)(file_obj.write):
            print('stdout to file')
    print('stdout to console')


    # stderr test
    with open('temp.stderr.log', 'w') as file_obj:
        with RedirectStdMsg(sys.stderr)(file_obj.write):
            sys.stderr.write('stderr to file')
    sys.stderr.write('stderr to console')

    # another way
    cs_stdout = RedirectStdMsg(sys.stdout)
    cs_stdout.start(open('temp.stdout.log', 'a').write)
    print('stdout to file 2')
    ...
    cs_stdout.stop()
    print('stdout to console 2')


if __name__ == '__main__':
    test_to_file()
    test_tk_without_stop_btn()
    test_tk_have_stop_btn()