Tkinter-logging texte dans le Widget texte

je veux faire une classe qui est capable de "journal" de texte dans un Widget Texte. Cette classe peut être utilisée par d'autres applications pour envoyer et afficher des logs au widget texte.

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..')

exemple D'Usage:

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

Mon problème maintenant est que je ne sais pas où mettre le mainloop. Cet enregistreur doit fonctionner "en arrière-plan" et il doit être possible d'écrire log à tout moment jusqu'à ce que la fenêtre soit fermée.

1
demandé sur oXOo 2014-07-08 12:05:14

2 réponses

j'ai eu un peu de mal avec cela, mais j'ai convergé sur les recommandations ici:

et j'ai un exemple ci-dessous que j'ai créé pour élucider le concept de logging à un contrôle GUI en utilisant Tkinter. L'exemple ci-dessous se connecte à un contrôle de texte comme vous le demandez, mais vous pouvez envoyer des messages de log à d'autres composants de GUI en remplaçant/copiant la classe MyHandlerText avec d'autres classes de handler comme MyHandlerLabel , MyHandlerListbox , etc. (choisissez vos propres noms pour les classes handler). Alors vous auriez un handler pour une variété de contrôles de GUI d'intérêt. Le grand moment "a-ha" pour moi a été le module-niveau getLogger concept encouragé par 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("<ButtonRelease-1>", 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()
2
répondu rob_7cc 2016-05-16 10:24:24

Dans ce cas, vous avez créé un composant qui serait utilisé dans une application. Le mainloop serait appelé dans cette application et ils écriraient à votre widget log.

vous pouvez ajouter un exemple d'utilisation simple (comme celui que vous avez donné) et/ou des tests dans le même fichier python que TraceConsole en utilisant quelque chose comme

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

je fais habituellement quelque chose comme ça pour tester un composant tkinter par lui-même avant d'incorporer dans mon application.

0
répondu RyGuyinCA 2014-07-09 21:42:38