如何解决将标准输出从多处理重定向到Tkinter文本小部件
我有点困在这里。我已经阅读了很多堆栈溢出线程,但对该主题没有任何进一步的了解。
我的目标是拥有一个Tinter GUI,该GUI在某个时候在新Process中启动一个功能,并将该功能中的每个打印重定向到Guis Text小部件。有一个管道和队列,但我不熟悉如何正确使用它们。我找到了一个可行的解决方案here,但这仅适用于Python3。不幸的是,我必须使用Python 2.7 ...
有人可以帮忙吗?
我的示例代码:
from Tkinter import *
import multiprocessing as mp
import time
import sys
class Gui(object):
def __init__(self):
self.a=Tk()
b1=Button(self.a,text="Process 1",command=self.func)
b1.grid(row=0,column=0,pady=10,padx=10,sticky=SE)
self.messages=Text(
self.a,height=2.5,width=30,bg="light cyan",state=NORMAL)
self.messages.grid(row=1,columnspan=3)
sys.stdout = self.StdoutRedirector(self.messages)
sys.stderr = self.StdoutRedirector(self.messages)
self.a.mainloop()
class StdoutRedirector(object):
def __init__(self,text_widget):
self.output = text_widget
def write(self,string):
self.output.config(state=NORMAL)
self.output.update_idletasks()
self.output.insert('end',string)
self.output.see('end')
self.output.config(state=DISABLED)
def flush(self):
pass
def func(self):
print("test")
proc=mp.Process(target=go)
proc.start()
def go():
for i in range(0,10):
time.sleep((1))
print(i)
if __name__ == "__main__":
Gui()
解决方法
您的代码中的问题是您无法在mainloop之外更改tkinter小部件的内容。我发现的一种解决方案是将stdout和stderr重定向到Queue,并定期读取mainloop中这些队列的内容以更新文本小部件。定期阅读使用方法.after(<delay in ms>,<callback>)
。
from Tkinter import *
import multiprocessing as mp
import time
import sys
class StdoutRedirector(object):
def __init__(self,queue):
self.output = queue
def write(self,string):
self.output.put(string)
def flush(self):
pass
class Gui(object):
def __init__(self):
self.a=Tk()
b1 = Button(self.a,text="Process 1",command=self.func)
b1.grid(row=0,column=0,pady=10,padx=10,sticky=SE)
self.messages=Text(self.a,height=2.5,width=30,bg="light cyan",state=NORMAL)
self.messages.grid(row=1,columnspan=3)
self.messages.tag_configure('error',foreground='red')
# queues to get the stdout and stderr
self.stdout = mp.Queue()
self.stderr = mp.Queue()
self.proc = None # process
self.a.mainloop()
def stdout_update(self):
self.messages.configure(state=NORMAL)
while not self.stdout.empty(): # display stdout
self.messages.insert('end',self.stdout.get(False))
while not self.stderr.empty(): # display stderr
self.messages.insert('end',self.stderr.get(False),'error')
self.messages.configure(state=DISABLED)
if self.proc.is_alive(): # the process is not finished,schedule the next display update
self.a.after(100,self.stdout_update)
def func(self):
self.proc = mp.Process(target=go,args=(self.stdout,self.stderr))
self.proc.start()
self.stdout_update() # launch display update
def go(queue_out,queue_err):
# redirect stdout and stderr to queues
sys.stdout = StdoutRedirector(queue_out)
sys.stderr = StdoutRedirector(queue_err)
for i in range(0,2):
time.sleep(1)
print(i)
1/0 # to test the stderr
if __name__ == "__main__":
Gui()
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。