我有四个文本框和最多四个进程,我将开始使用多处理模块。 我可以让进程正确执行,但我真的很想将每个进程的所有输出重定向到不同的 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()