【发布时间】:2011-02-24 06:28:03
【问题描述】:
我正在使用基于现有 Python bdb 模块的 Python/Tkinter 构建基于 GUI 的应用程序。在此应用程序中,我想使控制台中的所有 stdout/stderr 静音并将其重定向到我的 GUI。为了实现这个目的,我编写了一个专门的 Tkinter.Text 对象(代码在文章末尾)。
基本思想是,当将某些内容写入 sys.stdout 时,它会在“文本”中显示为黑色的一行。如果将某些内容写入 sys.stderr,它将在“文本”中显示为红色的一行。写完内容后,文本总是向下滚动以查看最近的行。
我目前正在使用 Python 2.6.1。在 Mac OS X 10.5 上,这似乎工作得很好。我的问题为零。然而,在 RedHat Enterprise Linux 5 上,我在脚本运行期间相当可靠地遇到了分段错误。分段错误并不总是发生在同一个地方,但它几乎总是发生。如果我从代码中注释掉 sys.stdout= 和 sys.stderr= 行,分段错误似乎就消失了。
我确信我可能不得不求助于其他方法,但是任何人都可以看到我在这里做的任何明显错误的事情可能导致这些分段错误吗?它快把我逼疯了。谢谢!
PS - 我意识到将 sys.stderr 重定向到 GUI 可能不是一个好主意,但即使我只重定向 sys.stdout 而不是 sys.stderr,我仍然会遇到分段错误。我也意识到我现在允许文本无限增长。
class ConsoleText(tk.Text):
'''A Tkinter Text widget that provides a scrolling display of console
stderr and stdout.'''
class IORedirector(object):
'''A general class for redirecting I/O to this Text widget.'''
def __init__(self,text_area):
self.text_area = text_area
class StdoutRedirector(IORedirector):
'''A class for redirecting stdout to this Text widget.'''
def write(self,str):
self.text_area.write(str,False)
class StderrRedirector(IORedirector):
'''A class for redirecting stderr to this Text widget.'''
def write(self,str):
self.text_area.write(str,True)
def __init__(self, master=None, cnf={}, **kw):
'''See the __init__ for Tkinter.Text for most of this stuff.'''
tk.Text.__init__(self, master, cnf, **kw)
self.started = False
self.write_lock = threading.Lock()
self.tag_configure('STDOUT',background='white',foreground='black')
self.tag_configure('STDERR',background='white',foreground='red')
self.config(state=tk.DISABLED)
def start(self):
if self.started:
return
self.started = True
self.original_stdout = sys.stdout
self.original_stderr = sys.stderr
stdout_redirector = ConsoleText.StdoutRedirector(self)
stderr_redirector = ConsoleText.StderrRedirector(self)
sys.stdout = stdout_redirector
sys.stderr = stderr_redirector
def stop(self):
if not self.started:
return
self.started = False
sys.stdout = self.original_stdout
sys.stderr = self.original_stderr
def write(self,val,is_stderr=False):
#Fun Fact: The way Tkinter Text objects work is that if they're disabled,
#you can't write into them AT ALL (via the GUI or programatically). Since we want them
#disabled for the user, we have to set them to NORMAL (a.k.a. ENABLED), write to them,
#then set their state back to DISABLED.
self.write_lock.acquire()
self.config(state=tk.NORMAL)
self.insert('end',val,'STDERR' if is_stderr else 'STDOUT')
self.see('end')
self.config(state=tk.DISABLED)
self.write_lock.release()
【问题讨论】:
-
顺便说一句,我建议不要在所有情况下都自动向下滚动。如果用户向上滚动查看某物,然后添加了一个新项目,那么当他们正在查看的内容移出视图时,他们将是一个不开心的用户。我使用的算法是,如果在输入新文本之前最后一行是可见的,我会自动滚动。否则我不会。
-
好电话。我敢肯定,它很快就会出现在我的“待修复”列表中。
标签: python redirect segmentation-fault stdout tkinter