我已经在dll(Windows 7)中embeddedpython解释器(2.7.6),作为插件加载在本地主机程序,它有自己的用户界面。 Python脚本文件由dll执行,脚本文件stderr被redirect到一个文件,另一个脚本被导入。 在这个脚本中(下面的代码)是一个创buildTkinter窗口的类,并且具有写入Tkinter文本窗口部件的write()方法。 Stdout被这个类redirect到它自己。 该类在线程中运行。
下面的代码在非embedded式python导入时效果很好。 当导入到embedded式python时,窗口出现,并显示输出,无论何时打印到标准输出,但否则窗口无响应(没有响应)。 斯德哥尔德是空的。
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 "---------------"
我也试图在subprocess中启动它,并写入它的stdin。 这个时间窗口保持响应,但输出不出现在输出窗口,直到主机应用程序退出。 没有什么stderr。 这是我添加到上面的脚本结束的代码:
for line in sys.stdin: sys.stdout.write(line)
这是我用来启动subprocess和redirect标准输出的代码:
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"
主要问题是:
什么是最好的方法? 而如何做到这一点?
额外的问题:
1)为什么我的tkinter输出窗口进入没有响应的状态,但仍然更新输出打印时不作为subprocess启动? 可以做些什么来使其响应?
2)在这种情况下如何利用subprocessstdin?
我真的很想在没有子处理的情况下工作,对于这样简单的输出窗口来说没问题,但是我想用一些更复杂的接口来构buildUI,并通过stdin工作,stdout并不是首选。
在这里找到解决办法:
Python线程不能在C ++应用程序嵌入式解释器中运行
在嵌入DLL中释放GIL使Tkinter窗口无需子处理即可响应。 在我的特殊情况下,我知道从某个时候开始,所有没有放在自己线程中的python代码只会响应从dll调用的回调函数,所以它应该是安全的。