Python 将stdout重定向到带有线程的Tkinter文本小部件时出现问题

Python 将stdout重定向到带有线程的Tkinter文本小部件时出现问题,python,multithreading,python-2.7,tkinter,stdout,Python,Multithreading,Python 2.7,Tkinter,Stdout,我的程序只在重定向sys.stdout后打印内容时,才会按预期运行,否则程序会冻结,这是为什么?这是虫子吗 代码: 如果您未注释这一行,则此脚本有效:print'hey' 顺便说一下,我的操作系统是Windows7,我对这个想法进行了修改,并找到了两种方法使其工作 1) 即使不是线程安全的,您的方法也可以工作。唯一的问题似乎是在开始打印到小部件之前需要初始化应用程序。如果您想“立即”启动第二个线程,而不是从某个回调开始,这对我来说很有用: root.after(100, thread1.star

我的程序只在重定向
sys.stdout
后打印内容时,才会按预期运行,否则程序会冻结,这是为什么?这是虫子吗

代码:

如果您未注释这一行,则此脚本有效:
print'hey'


顺便说一下,我的操作系统是Windows7,我对这个想法进行了修改,并找到了两种方法使其工作

1) 即使不是线程安全的,您的方法也可以工作。唯一的问题似乎是在开始打印到小部件之前需要初始化应用程序。如果您想“立即”启动第二个线程,而不是从某个回调开始,这对我来说很有用:

root.after(100, thread1.start)
2) 第二种更干净的方法基于@falsetru链接的示例。但是,它要求您以合理的速度打印到标准输出,这样更新就不会阻塞它

from Tkinter import *
import threading
import Queue # This is thread safe
import time

class Std_redirector():
    def __init__(self, widget):
        self.widget = widget

    def write(self,string):
        self.widget.write(string)

class ThreadSafeText(Text):
    def __init__(self, master, **options):
        Text.__init__(self, master, **options)
        self.queue = Queue.Queue()
        self.update_me()

    def write(self, line):
        self.queue.put(line)

    def update_me(self):
        while not self.queue.empty():
            line = self.queue.get_nowait()
            self.insert(END, line)
            self.see(END)
            self.update_idletasks()
        self.after(10, self.update_me)

def func():
    i = 0
    while True:
        i += 1
        print i
        time.sleep(0.01)

root = Tk()
text = ThreadSafeText(root)
text.pack()
sys.stdout = Std_redirector(text)

thread1 = threading.Thread(target=func)
thread1.start()

root.mainloop()

根据我在其他GUI工具包中的经验,我想使用
root.after\u idle()
,但它并没有像我预期的那样工作。

它对我有效-直接在Python中。在
DreamPie
pythonshell中,类似于
IDLE
我得到了错误
“Std\u redirector”对象没有属性“flush”
,但它仍然工作。(LinuxMint,Python2.7.5)@furas在Windows7中的Python2.7这里没有…@furas-oh你真的评论了
打印“嘿”
行吗。。。顺便说一句,只需运行更新的code@KDawG的新版本(和旧版本一样)可以使用和不使用
打印“嘿”
,但我使用Linux。这可能只是Windows的问题。谢谢你的帮助,顺便问一下,这是一个错误吗?我不知道。从Tk开始。但根据其他GUI库的经验,无论如何,您都不应该在主GUI线程之外更新GUI。通常使用事件将调用传播到主GUI线程,但这在Tkinter中也不适用。
from Tkinter import *
import threading
import Queue # This is thread safe
import time

class Std_redirector():
    def __init__(self, widget):
        self.widget = widget

    def write(self,string):
        self.widget.write(string)

class ThreadSafeText(Text):
    def __init__(self, master, **options):
        Text.__init__(self, master, **options)
        self.queue = Queue.Queue()
        self.update_me()

    def write(self, line):
        self.queue.put(line)

    def update_me(self):
        while not self.queue.empty():
            line = self.queue.get_nowait()
            self.insert(END, line)
            self.see(END)
            self.update_idletasks()
        self.after(10, self.update_me)

def func():
    i = 0
    while True:
        i += 1
        print i
        time.sleep(0.01)

root = Tk()
text = ThreadSafeText(root)
text.pack()
sys.stdout = Std_redirector(text)

thread1 = threading.Thread(target=func)
thread1.start()

root.mainloop()