Sono in procinto di creare un'applicazione basata su GUI con Python/Tkinter che si basa sul modulo bdb Python esistente. In questa applicazione, voglio silenziare tutto stdout/stderr dalla console e reindirizzare la mia GUI. Per raggiungere questo scopo, ho scritto un oggetto specializzato Tkinter.Text (codice alla fine del post).Errore di segmentazione durante il reindirizzamento di sys.stdout a Tkinter.Text widget
L'idea di base è che quando qualcosa viene scritto su sys.stdout, viene visualizzato come una linea nel "Testo" con il colore nero. Se qualcosa viene scritto su sys.stderr, viene visualizzato come una linea nel "Testo" con il colore rosso. Non appena viene scritto qualcosa, il testo scorre sempre verso il basso per visualizzare la riga più recente.
Attualmente sto usando Python 2.6.1. Su Mac OS X 10.5, sembra funzionare alla grande. Ho avuto zero problemi con esso. Su RedHat Enterprise Linux 5, tuttavia, ho ottenuto un errore di segmentazione in modo affidabile durante l'esecuzione di uno script. L'errore di segmentazione non si verifica sempre nello stesso punto, ma si verifica quasi sempre. Se commento le linee sys.stdout=
e sys.stderr=
dal mio codice, gli errori di segmentazione sembrano andare via.
Sono sicuro che ci sono altri modi intorno a questo che probabilmente dovrò ricorrere a, ma qualcuno può vedere qualcosa che sto facendo clamorosamente sbagliato qui che potrebbe causare questi errori di segmentazione? Mi sta facendo impazzire. Grazie!
PS - Mi rendo conto che il reindirizzamento di sys.stderr alla GUI potrebbe non essere una buona idea, ma ottengo ancora errori di segmentazione anche quando reindirizzo solo sys.stdout e non sys.stderr. Mi rendo anche conto che sto permettendo che il testo cresca indefinitamente al momento.
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()
solo a parte, vorrei suggerire * not * automaticamente lo scorrimento verso il basso in tutti i casi. Se un utente ha fatto scorrere verso l'alto per guardare qualcosa e poi viene aggiunto un nuovo elemento, sarà un utente infelice quando ciò che sta guardando si sposta fuori dalla vista. L'algoritmo che uso è, se l'ultima riga è visibile prima di inserire il nuovo testo, si scorre automaticamente. Altrimenti no. –
Buona chiamata. Sono sicuro che uno sarebbe apparso nella mia lista "To Fix" abbastanza presto. –