Python multiprocessing redirect stdout of a child process to a Tkinter Text -
i'm trying use tkinter gui launch child process , display stdout/stderr output text widget. initially, thought sys.stdout can redirected text widget setting "sys.stdout = text_widget" seems not. comes error: "text instance has no attribute 'flush'".
i checked online , got solutions, using queue communicate child process. however, none of them fit case because of special requirement:
- the child process should better launched "multiprocessing.process" because easier use shared variables, makes subprocess solutions usable.
- the codes of child process there quite lot "print" inside, don't want modify them "queue.put()" or else.
in case, come solution of getting "multiprocessing.process"'s "print" output , display tkinter text? many thanks!
an example code of case follows:
import sys import time multiprocessing import process 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()
it still possible use queues without having rid of of print statements. can use process dependent stdout redirect this. solution below uses queue subclass mimic stdout. queue monitored thread looks new text gets pumped text widget.
import sys import time multiprocessing import process multiprocessing.queues import queue threading import thread tkinter import * # function takes text widget , queue inputs. # functions waiting on new data entering queue, when # finds new data insert text widget def text_catcher(text_widget,queue): while true: text_widget.insert(end, queue.get()) # queue behaves 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): # line redirects stdout inside current process sys.stdout = q # or sys.stdout = sys.__stdout__ if want print child terminal print 'child running' def test_parent(q): # again redirects inside current (main) process # commenting out cause child write 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 , start text monitor monitor = thread(target=text_catcher,args=(gui_txt,q)) monitor.daemon = true monitor.start() gui_root.mainloop()
Comments
Post a Comment