Tkinter – registro de texto en Widget de texto

Quiero hacer una clase que pueda “registrar” el texto en un widget de texto. Otras aplicaciones podrían usar esta clase para enviar y mostrar registros al widget de texto.

class TraceConsole(): def __init__(self): # Init the main GUI window self._logFrame = Tk.Frame() self._log = Tk.Text(self._logFrame, wrap=Tk.NONE, setgrid=True) self._scrollb = Tk.Scrollbar(self._logFrame, orient=Tk.VERTICAL) self._scrollb.config(command = self._log.yview) self._log.config(yscrollcommand = self._scrollb.set) # Grid & Pack self._log.grid(column=0, row=0) self._scrollb.grid(column=1, row=0, sticky=Tk.S+Tk.N) self._logFrame.pack() def log(self, msg, level=None): # Write on GUI self._log.insert('end', msg + '\n') def exitWindow(self): # Exit the GUI window and close log file print('exit..') 

Ejemplo de uso:

 t = TraceConsole() t.log('hello world!') 

Mi problema ahora es que no sé dónde colocar el mainloop. Este registrador debe ejecutarse “en segundo plano” y será posible escribir el registro en cualquier momento hasta que se cierre la ventana.

Luché con esto por un tiempo, pero convergí en las recomendaciones aquí:

  • Facilidad de registro para Python

  • wxPython: Cómo redirigir el módulo de registro de Python a un TextCtrl

Y tengo un ejemplo a continuación que creé para dilucidar el concepto de registro en un control GUI usando Tkinter. El ejemplo a continuación se registra en un control de texto a medida que lo solicita, pero puede enviar mensajes de registro a otros componentes de la GUI al reemplazar / copiar la clase MyHandlerText con otras clases de controlador como MyHandlerLabel , MyHandlerListbox , etc. (elija sus propios nombres para las clases de controlador) . Entonces tendrías un manejador para una variedad de controles GUI de interés. El gran momento “a-ha” para mí fue el concepto getLogger nivel de getLogger alentado por python.org.

 import Tkinter import logging import datetime # this item "module_logger" is visible only in this module, # (but you can also reference this getLogger instance from other modules and other threads by passing the same argument name...allowing you to share and isolate loggers as desired) # ...so it is module-level logging and it takes the name of this module (by using __name__) # recommended per https://docs.python.org/2/library/logging.html module_logger = logging.getLogger(__name__) class simpleapp_tk(Tkinter.Tk): def __init__(self,parent): Tkinter.Tk.__init__(self,parent) self.parent = parent self.grid() self.mybutton = Tkinter.Button(self, text="ClickMe") self.mybutton.grid(column=0,row=0,sticky='EW') self.mybutton.bind("", self.button_callback) self.mytext = Tkinter.Text(self, state="disabled") self.mytext.grid(column=0, row=1) def button_callback(self, event): now = datetime.datetime.now() module_logger.info(now) class MyHandlerText(logging.StreamHandler): def __init__(self, textctrl): logging.StreamHandler.__init__(self) # initialize parent self.textctrl = textctrl def emit(self, record): msg = self.format(record) self.textctrl.config(state="normal") self.textctrl.insert("end", msg + "\n") self.flush() self.textctrl.config(state="disabled") if __name__ == "__main__": # create Tk object instance app = simpleapp_tk(None) app.title('my application') # setup logging handlers using the Tk instance created above # the pattern below can be used in other threads... # ...to allow other thread to send msgs to the gui # in this example, we set up two handlers just for demonstration (you could add a fileHandler, etc) stderrHandler = logging.StreamHandler() # no arguments => stderr module_logger.addHandler(stderrHandler) guiHandler = MyHandlerText(app.mytext) module_logger.addHandler(guiHandler) module_logger.setLevel(logging.INFO) module_logger.info("from main") # start Tk app.mainloop() 

En este caso, ha creado un componente que se usaría dentro de una aplicación. Se llamaría mainloop en esa aplicación y escribirían en su widget de registro.

Podría agregar algunos ejemplos de uso simple (como el que dio) y / o pruebas en el mismo archivo de Python que TraceConsole usando algo como

 if __name__ == '__main__': m = tkinter.Tk() t = TraceConsole() t.log('hello world!') m.mainloop() 

Normalmente hago algo como esto para poder probar un componente tkinter por sí mismo antes de incorporarlo en mi aplicación.