将进程从多处理重定向到单独的 wx.文本控制



我有四个文本框和最多四个进程,我将开始使用多处理模块。 我可以让进程正确执行,但我真的很想将每个进程的所有输出重定向到不同的 wx。TextCtrl,这样我就可以看到整个解决方案过程中发生了什么。 我已经成功地用单线程和 sys.stdout 重定向完成了此操作,如

http://www.velocityreviews.com/forums/t515815-wxpython-redirect-the-stdout-to-a-textctrl.html

但是类似的想法不适用于流程。 有人可以破解我这个问题的简单解决方案吗? 我无法想象我是唯一一个遇到过这个问题的人。

据我了解,在wxPython土地上,您通常希望从线程运行进程。因此,您从进程到线程以及从线程返回到wxPython进行通信。我会使用某种命名方案将每个潜在的进程与文本控件(也许是 1-4?)相关联,并将其传递回将使用 wx 的线程。CallAfter 或 wx。发布事件以告诉 wx 进行更新。

您也可以使用简单的 Python 套接字服务器来完成此操作。将消息发布到服务器,其标头说明它属于哪个文本控件。在wx部分,你可以有一个wx。计时器检查套接字服务器是否有新消息,并根据需要进行更新。

对于那些感兴趣的人,这里有一个工作代码片段,可以完成我最初的问题。 它是一种享受。

此代码创建一个包装进程的线程。 在进程的 run() 函数中,stderr 和 stdout 使用重定向类重定向到管道。 管道可以酸洗,这是在进程的 run() 函数中使用它们的先决条件。

然后,只要有输出等待,线程就只是坐下来并从管道中提取输出。 从管道中提取的文本将写入 wx。使用 wx 的文本控制。调用后函数。 请注意,这是一个非阻塞调用,实际上这里的所有代码都是非阻塞的,这使得响应式 GUI。 请注意重定向类中的 flush() 函数来重定向 stderr。

注意

:需要注意的一点是,如果您尝试以过高的吞吐量使用管道进行读写,GUI 将锁定。 但只要你的输出相当慢,就没有问题

import wx
import sys
import time
from multiprocessing import Pipe, Process
from threading import Thread
class RedirectText2Pipe(object):
    def __init__(self, pipe_inlet):
        self.pipe_inlet = pipe_inlet
    def write(self, string):
        self.pipe_inlet.send(string)
    def flush(self):
        return None
class Run1(Process):
    def __init__(self, pipe_inlet):
        Process.__init__(self)
        self.pipe_std = pipe_inlet
    def run(self):
        redir = RedirectText2Pipe(self.pipe_std)
        sys.stdout = redir
        sys.stderr = redir
        for i in range(100):
            time.sleep(0.01)
            print i,'Hi'
class RedirectedWorkerThread(Thread):
    """Worker Thread Class."""
    def __init__(self, stdout_target):
        """Init Worker Thread Class."""
        Thread.__init__(self)
        self.stdout_target_ = stdout_target
    def run(self):
        """
        In this function, actually run the process and pull any output from the 
        pipes while the process runs
        """
        pipe_outlet, pipe_inlet = Pipe(duplex = False)
        p = Run1(pipe_inlet)
        p.daemon = True
        p.start()
        while p.is_alive():
            #Collect all display output from process
            while pipe_outlet.poll():
                wx.CallAfter(self.stdout_target_.WriteText, pipe_outlet.recv())
class MainFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self,None)
        self.txt1 = wx.TextCtrl(self, style = wx.TE_MULTILINE|wx.TE_READONLY)
        self.txt2 = wx.TextCtrl(self, style = wx.TE_MULTILINE|wx.TE_READONLY)
        self.txt3 = wx.TextCtrl(self, style = wx.TE_MULTILINE|wx.TE_READONLY)
        self.btn = wx.Button(self, label='Run')
        self.btn.Bind(wx.EVT_BUTTON, self.OnStart)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.AddMany([(self.txt1,1,wx.EXPAND),(self.txt2,1,wx.EXPAND),(self.txt3,1,wx.EXPAND),self.btn])
        self.SetSizer(sizer)
    def OnStart(self, event):
        t1 = RedirectedWorkerThread(self.txt1)
        t1.daemon = True
        t1.start()
        t2 = RedirectedWorkerThread(self.txt2)
        t2.daemon = True
        t2.start()
        t3 = RedirectedWorkerThread(self.txt3)
        t3.daemon = True
        t3.start()
if __name__ == '__main__':
    app = wx.App(False)
    frame = MainFrame() 
    frame.Show(True) 
    app.MainLoop()

最新更新