Python多重处理将子进程的标准输出重定向到Tkinter文本 [英] Python multiprocessing redirect stdout of a child process to a Tkinter Text

查看:149
本文介绍了Python多重处理将子进程的标准输出重定向到Tkinter文本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Tkinter GUI启动子进程并将其stdout/stderr输出显示到Text小部件.最初,我认为可以通过设置"sys.stdout = text_widget"轻松地将sys.stdout重定向到Text小部件,但似乎不行.出现错误:文本实例没有属性'flush'".

I'm trying to use Tkinter GUI to launch a child process and display it stdout/stderr output to a Text widget. Initially, I thought the sys.stdout can be easily redirected to the Text widget by setting "sys.stdout = text_widget" but seems not. It comes to an error: "Text instance has no attribute 'flush'".

我在线检查并得到了一些解决方案,例如使用队列与子进程进行通信.但是,由于我的特殊要求,它们都不适合我的情况:

I checked online and got some solutions, like using a Queue to communicate with the child process. However, none of them fit my case because of my special requirement:

  1. 最好通过"multiprocessing.Process"启动子进程,因为使用共享变量会更容易,这将使子进程解决方案变得可用.
  2. 子进程的代码已经存在,里面有很多打印",所以我不想将它们修改为"Queue.put()"之类的东西.

在这种情况下,谁能找到一种解决方案来获取"multiprocessing.Process"的"print"输出并显示为Tkinter Text?非常感谢!

In this case, could anyone come to a solution of getting a "multiprocessing.Process"'s "print" output and display to a Tkinter Text? Many thanks!

我的案例的示例代码如下:

An example code of my case is a follows:

import sys
import time
from multiprocessing import Process
from Tkinter import *

def test_child():
    print 'child running'

def test_parent():
    print 'parent running'
    time.sleep(0.5)
    Process(target=test_child).start()

def set_txt(msg):
    gui_txt.insert(END, str(msg))
    gui_txt.see(END)

if __name__ == '__main__':
    gui_root = Tk()
    gui_txt = Text(gui_root)
    gui_txt.pack()
    gui_btn = Button(gui_root, text='Test', command=test_parent)
    gui_btn.pack()

    gui_txt.write = set_txt
    sys.stdout = gui_txt

    gui_root.mainloop()

推荐答案

仍然可以使用队列而不必摆脱所有print语句.您可以使用Process依赖stdout重定向来执行此操作.下面的解决方案使用Queue子类来模仿stdout.然后,该队列由一个线程监视,该线程寻找被泵送到文本小部件中的新文本.

It is still possible to use queues without having to get rid of all of your print statements. You can use a Process dependent stdout redirect to do this. The solution below uses a Queue subclass to mimic stdout. That queue is then monitored by a thread that looks for new text that gets pumped into the text widget.

import sys
import time
from multiprocessing import Process
from multiprocessing.queues import Queue
from threading import Thread
from Tkinter import *

# This function takes the text widget and a queue as inputs.
# It functions by waiting on new data entering the queue, when it 
# finds new data it will insert it into the text widget 
def text_catcher(text_widget,queue):
    while True:
        text_widget.insert(END, queue.get())

# This is a Queue that behaves like stdout
class StdoutQueue(Queue):
    def __init__(self,*args,**kwargs):
        Queue.__init__(self,*args,**kwargs)

    def write(self,msg):
        self.put(msg)

    def flush(self):
        sys.__stdout__.flush()


def test_child(q):
    # This line only redirects stdout inside the current process 
    sys.stdout = q
    # or sys.stdout = sys.__stdout__ if you want to print the child to the terminal
    print 'child running'

def test_parent(q):
    # Again this only redirects inside the current (main) process
    # commenting this like out will cause only the child to write to the widget 
    sys.stdout = q                                                                                                                                                                                                                                                         
    print 'parent running'
    time.sleep(0.5)
    Process(target=test_child,args=(q,)).start()

if __name__ == '__main__':
    gui_root = Tk()
    gui_txt = Text(gui_root)
    gui_txt.pack()
    q = StdoutQueue()
    gui_btn = Button(gui_root, text='Test', command=lambda:test_parent(q),)
    gui_btn.pack()

    # Instantiate and start the text monitor
    monitor = Thread(target=text_catcher,args=(gui_txt,q))
    monitor.daemon = True
    monitor.start()

    gui_root.mainloop()

这篇关于Python多重处理将子进程的标准输出重定向到Tkinter文本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆