Jestem w trakcie budowania aplikacji opartej na interfejsie graficznym z Pythonem/Tkinter, która opiera się na istniejącym module bdb Pythona. W tej aplikacji chcę wyciszyć wszystkie stdout/stderr z konsoli i przekierować ją do mojego GUI. Aby osiągnąć ten cel, napisałem specjalistyczny obiekt Tkinter.Text (kod na końcu postu).Błąd segmentacji podczas przekierowywania sys.stdout do widżetu Tkinter.Text
Podstawową ideą jest, że gdy coś jest napisane do sys.stdout, pojawia się jako linia w "Tekst" z kolorem czarnym. Jeśli coś jest napisane do sys.stderr, pojawia się jako linia w "Text" z kolorem czerwonym. Gdy tylko coś zostanie napisane, tekst zawsze przewija się w dół, aby wyświetlić najnowszą linię.
Używam Python 2.6.1 w tej chwili. W systemie Mac OS X 10.5 wygląda na to, że działa świetnie. Nie miałem z tym problemów. Jednak w RedHat Enterprise Linux 5 całkiem niezawodnie otrzymuję błąd segmentacji podczas uruchamiania skryptu. Błąd segmentacji nie zawsze występuje w tym samym miejscu, ale prawie zawsze występuje. Jeśli skomentuję linie sys.stdout=
i sys.stderr=
z mojego kodu, błędy segmentacji wydają się znikać.
Jestem pewien, że są inne sposoby obejścia tego, do czego prawdopodobnie będę musiał się odwoływać, ale czy ktoś może zobaczyć coś, co robię rażąco nie tak tutaj, co może być przyczyną tych błędów segmentacji? To doprowadza mnie do szału. Dzięki!
PS - Rozumiem, że przekierowanie sys.stderr do GUI może nie być dobrym pomysłem, ale nadal dostaję błędy segmentacji, nawet gdy przekierowuję tylko sys.stdout, a nie sys.stderr. Zdaję sobie również sprawę, że pozwalam, aby tekst narastał w nieskończoność.
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()
tak na marginesie sugerowałbym * nie * automatyczne przewijanie we wszystkich przypadkach. Jeśli użytkownik przewinął do góry, aby na coś spojrzeć, a następnie dodano nowy element, będzie nieszczęśliwym użytkownikiem, gdy to, na co patrzy, znika z widoku. Używam algorytmu, jeśli ostatnia linia jest widoczna przed wprowadzeniem nowego tekstu, automatycznie przewijam. W przeciwnym razie nie. –
Dobra rozmowa. Jestem pewien, że wkrótce pojawi się na mojej liście "Naprawić". –