興味のある方のために、これが私の最初の質問が尋ねたことを実行する実用的なコードスニペットです。それは御馳走を動作します。
このコードは、プロセスをラップするスレッドを作成します。プロセスのrun()関数内で、stderrとstdoutはリダイレクトクラスを使用してパイプにリダイレクトされます。プロセスのrun()関数内でパイプを使用するための前提条件である、パイプをピクルスにすることができます。
次に、スレッドは、出力が待機している限り、パイプから出力を引き出します。パイプからプルされたテキストは、wx.CallAfter関数を使用してwx.TextCtrlに書き込まれます。これは非ブロッキング呼び出しであり、実際、ここにあるすべてのコードは非ブロッキングであるため、応答性の高いGUIが作成されることに注意してください。stderrもリダイレクトするredirectionクラスのflush()関数に注意してください。
注:注意すべき点の1つは、スループットが高すぎるパイプを使用して読み取りと書き込みを行おうとすると、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()