【发布时间】:2014-02-26 07:50:11
【问题描述】:
我在 dll (Windows 7) 中嵌入了 python 解释器 (2.7.6),它作为插件加载到具有自己的 ui 的本机主机程序中。 Python 脚本文件由 dll 执行,其中脚本文件 stderr 被重定向到一个文件并导入另一个脚本。在这个脚本(下面的代码)中是一个创建 Tkinter 窗口的类,并且具有写入 Tkinter 文本小部件的 write() 方法。 Stdout 由该类重定向到自身。该类在线程中运行。
以下代码在通过非嵌入式 python 导入时效果很好。导入嵌入式 python 时,只要将任何内容打印到标准输出,窗口就会出现并显示输出,否则窗口无响应(无响应)。 Stderr 为空。
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 "---------------"
我也尝试在子进程中启动它并写入它的标准输入。此时间窗口保持响应,但在主机应用程序退出之前,输出不会出现在输出窗口中。标准错误中没有任何内容。这是我在上面脚本末尾添加的代码:
for line in sys.stdin:
sys.stdout.write(line)
这是我用来启动子进程和重定向标准输出的代码:
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 输出窗口进入无响应状态,但在未作为子进程启动时打印输出时仍在更新?可以做些什么来让它响应?
2) 在这种情况下如何利用子进程标准输入?
我真的很想让它在没有子处理的情况下工作,对于这样简单的输出窗口来说没问题,但我想用更复杂的界面构建 ui,并且不首选通过 stdin 和 stdout 工作。
【问题讨论】:
-
您在启动子进程的代码中使用的反斜杠和路径规范不一致——
'C:\python27\python.exe python27\\stackoverflow_sub.py'。 -
谢谢。现在解决这个问题。虽然它不能解决问题。
-
@eryksun sys.stdin.readline() 在子处理时实际工作,它现在按预期工作。谢谢!奇怪的是,将 Tk 的东西移动到 setup 方法并从 run() 调用它在导入或子处理时像以前一样工作。当尝试按原样运行文件时,我在尝试打印时得到:“TclError:堆栈空间不足(无限循环?)”。它在第一次 Tkinter 交互时停止:self.text.config(state = NORMAL)
-
我认为路径规范应该是
'C:\\python27\\python.exe C:\\python27\\stackoverflow_sub.py'。 -
@martineau 脚本位于子文件夹 python27 中,相对于脚本子处理它。这有点令人困惑,所以为了清楚起见,我已经编辑了那个额外的文件夹。感谢您的提醒。
标签: python windows dll tkinter embed