I have embedded python interpreter (2.7.6) in dll (Windows 7) that is loaded as plugin in a native host program that has its own ui. Python script file is executed by dll, in that script file stderr is redirected to a file and another script is imported. In this script (code below) is a class that creates Tkinter window and and has write() method that writes to Tkinter text widget. Stdout is redirected by that class to itself. The class is run in thread.
Code below works great when imported by non-embedded python. When importing to embedded python, window appears and displays output whenever anything is printed to stdout, but otherwise the window is unresponsive (not responding). Stderr is empty.
import time
import threading
from Tkinter import *
from ScrolledText import *
class OutputWindow(threading.Thread):
'''Output window where stdout is re-directed. Inherits Thread'''
def __init__(self):
self.autoScroll = True
#root
self.root = Tk()
self.root.title("My output window")
Grid.rowconfigure(self.root, 0, weight = 0)
Grid.rowconfigure(self.root, 1, weight = 1)
Grid.columnconfigure(self.root, 0, weight = 1)
#frame for buttons
topframe = Frame(self.root, width = "250px", height = "10px")
topframe.grid(row = 0, sticky = E+W+N)
Grid.rowconfigure(topframe, 0, weight = 1)
#frame for text widget
botframe = Frame(self.root)
botframe.grid(row = 1, sticky = N+S+E+W)
Grid.rowconfigure(botframe, 0, weight = 1)
Grid.columnconfigure(botframe, 0, weight = 1)
#autoscroll bool button
self.autoScrollBtn = Button(topframe, text="AutoScroll", command = self.onAutoScroll)
self.autoScrollBtn.grid(row = 0, column = 0, sticky = W+E)
self.autoScrollBtn["relief"] = SUNKEN
#clear button
self.clearBtn = Button(topframe, text = "Clear", command = self.onClear)
self.clearBtn.grid(row = 0, column = 1, sticky = W+E)
#text widget with scrollbar
self.text = ScrolledText(botframe)
self.text.grid(row = 0, sticky = W+E+N+S)
self.text.config(state = DISABLED)
threading.Thread.__init__(self)
def onAutoScroll(self):
self.autoScroll = not self.autoScroll
if self.autoScroll:
self.autoScrollBtn["relief"] = SUNKEN
else:
self.autoScrollBtn["relief"] = RAISED
def onClear(self):
self.text.config(state = NORMAL)
self.text.delete(1.0, END)
self.text.config(state = DISABLED)
def write(self, txt):
'''write method for redirecting stdout.'''
#print txt
self.text.config(state = NORMAL)
self.text.insert(END,str(txt))
self.text.config(state = DISABLED)
if self.autoScroll:
self.text.see(END)
def run(self):
'''Thread.run method.'''
self.stdout_prev = sys.stdout
sys.stdout = self
self.root.mainloop()
sys.stdout = self.stdout_prev
self.windowOpen = False
out = OutputWindow()
out.start()
time.sleep(0.1) #wait for thread to start properly...
print "Start of output"
print "---------------"
I've also tried to launch this in subprocess and write to it's stdin. This time window remains responsive but output isn't appearing in output window until host application exits. Nothing in stderr. This is the code I added to end of script above:
for line in sys.stdin:
sys.stdout.write(line)
And this is the code I used to launch subprocess and redirect stdout:
class redirect():
def __init__(self, proc):
self.p = proc
def write(self, txt):
self.p.stdin.write(txt)
self.p.stdin.flush()
import subprocess
proc = subprocess.Popen('C:\\python27\\python.exe stackoverflow_sub.py', stdin = subprocess.PIPE)
sys.stdout = redirect(proc)
print "test redir"
Main question being:
What would be the best approach? And how to do it?
Extra questions:
1) Why my tkinter output window goes to not responding state but still updating when output is printed when not launching as subprocess? What can be done to make it responsive?
2) How to utilize the subprocess stdin in this case?
I'd really like to get it working without subprocessing, for such simple output window it is ok, but I'd like to build ui's with a bit more elaborate interfaces and working via stdin and stdout is not preferred.