简体   繁体   English

如何将python多处理过程输出发送到Tkinter gui

[英]How can I send python multiprocessing Process output to a Tkinter gui

I'm trying to get output from a python multiprocessing Process displayed in a Tkinter gui. 我正在尝试从Tkinter gui中显示的python多处理过程中获取输出。

I can send output from Processes via a gui to a command shell, for example by running the fllowing tiny script at a shell prompt: 我可以通过gui将进程的输出发送到命令shell,例如在shell提示符下运行fllowing tiny脚本:

from multiprocessing import Process  
import sys  

def myfunc(text):    
    print text  
    sys.stdout.flush() 

def f1():  
    p1 = Process(target = myfunc, args = ("Surprise",))  
    p1.start()  

def f2():  
    p2 = Process(target = myfunc, args = ("Fear",))  
    p2.start()  

def fp():  
    myfunc("... and an almost fanatical devotion to the Pope")  

a = Tk()  

b1 = Button(a, text="Process 1", command=f1)  
b1.grid(row=0, column=0, pady=10, padx=10, sticky=SE)  
b2 = Button(a, text="Process 2", command=f2)  
b2.grid(row=0, column=1, pady=10, padx=10, sticky=SE)  
b3 = Button(a, text="Parent", command=fp)  
b3.grid(row=0, column=2, pady=10, padx=10, sticky=SE)  

if __name__ == "__main__":  
    a.mainloop()

I can also send output from the parent to a Text box, for example by modifying the above by commenting out the flushing of stdout in myfunc 我也可以将输出发送到文本框,例如通过在myfunc中注释掉stdout来修改上面的内容

#    sys.stdout.flush()

and adding immediately after the "b3.grid..." line the following: 并在“b3.grid ...”之后立即添加以下内容:

class STDText(Text):
    def __init__(self, parent, cnf={}, **kw):
        Text.__init__(self, parent, cnf, **kw)
    def write(self, stuff):
        self.config(state=NORMAL)
        self.insert(END, stuff)
        self.yview_pickplace("end")
        self.config(state=DISABLED)

messages = STDText(a, height=2.5, width=30, bg="light cyan", state=DISABLED)   
messages.grid(row=1, column=0, columnspan=3)
sys.stdout = messages

However I can't figure out how to send output from the Processes to the text box. 但是,我无法弄清楚如何将进程的输出发送到文本框。 Am I missing something simple? 我错过了一些简单的事吗?

You could redirect stdout/stderr to a StringIO in myfunc(), then send whatever gets written into that StringIO back to the parent (as suggested by unutbu). 您可以将stdout / stderr重定向到myfunc()中的StringIO,然后将写入StringIO的任何内容发送回父级(如unutbu所示)。 See my answer to this question for one way of doing this redirection. 有关执行此重定向的一种方法,请参阅此问题的答案。

Since that example does a bit more than you need, here's a version that's more aligned with your stated goals: 由于该示例比您需要的更多,这里的版本更符合您的既定目标:

#!/usr/bin/env python
import sys
from cStringIO import StringIO
from code import InteractiveConsole
from contextlib import contextmanager
from multiprocessing import Process, Pipe

@contextmanager
def std_redirector(stdin=sys.stdin, stdout=sys.stdin, stderr=sys.stderr):
    tmp_fds = stdin, stdout, stderr
    orig_fds = sys.stdin, sys.stdout, sys.stderr
    sys.stdin, sys.stdout, sys.stderr = tmp_fds
    yield
    sys.stdin, sys.stdout, sys.stderr = orig_fds

class Interpreter(InteractiveConsole):
    def __init__(self, locals=None):
        InteractiveConsole.__init__(self, locals=locals)
        self.output = StringIO()
        self.output = StringIO()

    def push(self, command):
        self.output.reset()
        self.output.truncate()
        with std_redirector(stdout=self.output, stderr=self.output):
            try:
                more = InteractiveConsole.push(self, command)
                result = self.output.getvalue()
            except (SyntaxError, OverflowError):
                pass
            return more, result

def myfunc(conn, commands):
    output = StringIO()
    py = Interpreter()
    results = ""

    for line in commands.split('\n'):
        if line and len(line) > 0:
            more, result = py.push(line + '\n')
            if result and len(result) > 0:
                results += result

    conn.send(results)
    conn.close()

if __name__ == '__main__':
    parent_conn, child_conn = Pipe()

    commands = """
print "[42, None, 'hello']"

def greet(name, count):
    for i in range(count):
        print "Hello, " + name + "!"

greet("Beth Cooper", 5)
fugazi
print "Still going..."
"""
    p = Process(target=myfunc, args=(child_conn, commands))
    p.start()
    print parent_conn.recv()
    p.join()

The usual caveats about security apply here (ie, don't do this unless you can trust the sender of these code snippets to not do anything stupid/malicious). 关于安全性的常见警告适用于此(即,除非您可以信任这些代码段的发件人不做任何愚蠢/恶意的事情,否则不要这样做)。

Also note that you can simplify this a lot if you don't need to interpret an arbitrary mix of python expressions and statements. 另请注意,如果您不需要解释任意混合的python表达式语句,则可以对此进行简化。 If you only need to call a top-level function that generates some outputs, something like this may be more appropriate: 如果您只需要调用生成某些输出的顶级函数,那么这样的事情可能更合适:

def dosomething():
    print "Doing something..."

def myfunc(conn, command):
    output = StringIO()
    result = ""
    with std_redirector(stdout=output, stderr=output):
        try:
            eval(command)
            result = output.getvalue()
        except Exception, err:
            result = repr(err)

    conn.send(result)
    conn.close()

if __name__ == '__main__':
    parent_conn, child_conn = Pipe()
    command = "dosomething()"
    p = Process(target=myfunc, args=(child_conn, command))
    p.start()
    print parent_conn.recv()
    p.join()

You can pass (picklable) data between processes using a multiprocessing.Pipe . 您可以使用multiprocessing.Pipe在进程之间传递(可选择的)数据。 For example: 例如:

import Tkinter
import multiprocessing as mp

class STDText(Tkinter.Text):
    def __init__(self, parent, cnf={}, **kw):
        Tkinter.Text.__init__(self, parent, cnf, **kw)
    def write(self, stuff):
        self.config(state=Tkinter.NORMAL)
        self.insert(Tkinter.END, stuff)
        self.yview_pickplace("end")
        self.config(state=Tkinter.DISABLED)

def myfunc(conn,text):    
    conn.send(text)
    conn.close()

class Gui(object):
    def __init__(self):
        self.a=Tkinter.Tk()  
        b1=Tkinter.Button(self.a, text="Process 1", command=self.foo)  
        b1.grid(row=0, column=0, pady=10, padx=10, sticky=Tkinter.SE)  
        b2=Tkinter.Button(self.a, text="Process 2", command=self.bar)  
        b2.grid(row=0, column=1, pady=10, padx=10, sticky=Tkinter.SE)  
        b3=Tkinter.Button(self.a, text="Parent", command=self.baz)  
        b3.grid(row=0, column=2, pady=10, padx=10, sticky=Tkinter.SE)  
        self.messages=STDText(
            self.a, height=2.5, width=30, bg="light cyan", state=Tkinter.DISABLED)   
        self.messages.grid(row=1, column=0, columnspan=3)
        self.a.mainloop()        
    def call_myfunc(self,text):
        parent_conn, child_conn=mp.Pipe()
        proc=mp.Process(target=myfunc, args=(child_conn,text,))  
        proc.start()  
        self.messages.write(parent_conn.recv())
        proc.join()       
    def foo(self):
        self.call_myfunc('Foo\n')
    def bar(self):
        self.call_myfunc('Bar\n')        
    def baz(self):
        parent_conn, child_conn=mp.Pipe()
        myfunc(child_conn,'Baz\n')
        self.messages.write(parent_conn.recv())

if __name__ == "__main__":  
    Gui()

See Doug Hellman's tutorial on multiprocessing for more information. 有关详细信息,请参阅Doug Hellman的 multiprocessing 教程

Assuming that myfunc is called with the output of the process, just write myfunc like: 假设使用进程的输出调用myfunc ,只需编写myfunc,如:

def myfunc(text):    
    textwidget.insert("end", text)

where textwidget is a handle to the text widget textwidget是文本小部件的句柄

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Python多处理和tkinter - 如何连接这个过程(GUI和衍生过程)? - Python multiprocessing and tkinter - how to connect this process (GUI and spawned process)? 在Python中,如何在启动队列后将其发送到multiprocessing.Process? - In Python, how can I send a Queue to a multiprocessing.Process after it has already been started? 如何从衍生的进程(multiprocessing.Process)更新 Tkinter label? - How can I update Tkinter label from a spawned process (multiprocessing.Process)? 如何使用Python多处理池处理tarfile? - How can I process a tarfile with a Python multiprocessing pool? 如何避免 Tkinter GUI 在 Python3 中冻结? - How can i avoid Tkinter GUI freezing in Python3? 如何从 Python 多处理进程打印? - How can I print from a Python multiprocessing process? 如何在Python中使用tkinter使用GUI对计算器进行编程? - How can I program a calculator with a GUI using tkinter in Python? 如何在 GUI 中使用 Tkinter 在 Python 中显示过滤后的 DataFrame? - How can i show in GUI a filtered DataFrame in python with Tkinter? 如何压缩此 Python Tkinter GUI 输入代码? - How can I condense this Python Tkinter GUI input code? 多处理冻结/挂起Python中的Tkinter GUI - Multiprocessing freezes/hangs tkinter GUI in Python
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM