我正在使用Python/Tkinter构建基于GUI的应用程序,该应用程序基于现有的Python bdb模块。在此应用程序中,我希望将所有的stdout/stderr从控制台静音并重定向到我的GUI。为了实现这个目的,我编写了一个专门的Tkinter.Text对象(代码在帖子的末尾)。
基本思路是当有内容写入sys.stdout时,它会以黑色的形式显示在“Text”中。如果有内容写入sys.stderr,则以红色的形式显示在“Text”中。一旦有内容被写入,“Text”总是自动滚动到查看最新的行。
我目前使用的是Python 2.6.1。在Mac OS X 10.5上,这似乎非常好用。我没有遇到任何问题。但是,在RedHat Enterprise Linux 5上,我几乎总是在运行脚本时出现分段错误。分段错误不总是发生在相同的位置,但几乎总是发生。如果我从我的代码中注释掉
我相信还有其他方法可以解决这个问题,但有没有人能看出我在这里做错了什么,导致这些分段错误?这真让我抓狂。谢谢!
PS-我意识到将sys.stderr重定向到GUI可能不是一个好主意,但即使我只重定向sys.stdout而不是sys.stderr,我仍然会遇到分段错误。我也意识到目前允许“Text”无限增长。
基本思路是当有内容写入sys.stdout时,它会以黑色的形式显示在“Text”中。如果有内容写入sys.stderr,则以红色的形式显示在“Text”中。一旦有内容被写入,“Text”总是自动滚动到查看最新的行。
我目前使用的是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,我仍然会遇到分段错误。我也意识到目前允许“Text”无限增长。
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()