Segmentation fault while redirecting sys.stdout to Tkinter.Text widget

前端 未结 2 1545
暖寄归人
暖寄归人 2021-02-06 11:51

I\'m in the process of building a GUI-based application with Python/Tkinter that builds on top of the existing Python bdb module. In this application, I want to silence all std

2条回答
  •  难免孤独
    2021-02-06 12:24

    Alright, so I've managed to track down the problem. I was never able to recreate this problem on Mac OS X 10.5.8 where I originally developed the code. The segmentation faults only seem to occur on RedHat Enterprise Linux 5.

    It turns out that this piece of code is the culprit:

    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()
    

    I wish I had an explanation for why the segmentation faults are occurring, but I've found that constantly enabling and disabling the Text object is the culprit. If I change the above piece of code to this:

    def write(self,val,is_stderr=False):
    
            self.write_lock.acquire()
    
            self.insert('end',val,'STDERR' if is_stderr else 'STDOUT')
            self.see('end')
    
            self.write_lock.release()
    

    My segmentation faults go away when I remove the self.config(state=...) calls. The whole point of the self.config(state=...) calls was to make it so the user could not edit the Text field. When the Text field is in tk.DISABLED state though, calls to self.insert(...) do not work either.

    The workaround solution I've come up with is to leave the Text field enabled, but cause the Text field to ignore all keyboard input (thus giving the illusion of read-only behavior if the user attempts to use the keyboard). The easiest way to do this is to change the __init__ method to look like this (change the state to tk.NORMAL and change the binding for events):

    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.NORMAL)
            self.bind('',lambda e: 'break') #ignore all key presses
    

    Hope that helps anyone who runs into the same problem.

提交回复
热议问题