Python Logging to Tkinter Text Widget

后端 未结 6 1857
悲哀的现实
悲哀的现实 2020-12-14 16:46

Does any one out there have an example of how to setup logging in Python to a Tkinter Text Widget? I have seen this used in several apps but cannot figure out how to direct

6条回答
  •  谎友^
    谎友^ (楼主)
    2020-12-14 17:27

    I've bumped the same problem. The common solution found was like mentioned in this thread- bringing widget from GUI module to Logging.Handler.
    It was criticized as not safety, as a widget is passes to another thread (logging).
    The best solution found was using queue, made by Benjamin Bertrand: https://beenje.github.io/blog/posts/logging-to-a-tkinter-scrolledtext-widget/.
    I improved it a bit: queue should be created in logging handler, and passed to a GUI widget.

    import logger
    import queue
    
    
    class QueueHandler(logging.Handler):
        def __init__(self):
            super().__init__()
            self.log_queue = queue.Queue()
    
        def emit(self, record):
            # put a formatted message to queue
            self.log_queue.put(self.format(record))
    
    
    queue_handler = QueueHandler()
    logger.addHandler(queue_handler)
    
    

    So we have generally available logger, and every log message from any module will be passed to a queue_handler along with other handlers - to a file etc. Now we can import queue_handler to a widget.
    Most of the code is taken from the link above, I just changed the location of the original logging queue.

    from tkinter.scrolledtext import ScrolledText
    from  some_logging_module import queue_handler
    
    class ConsoleUi:
        """Poll messages from a logging queue and display them in a scrolled text widget"""
    
        def __init__(self, frame, queue):
            self.frame = frame
            # Create a ScrolledText wdiget
            self.console = ScrolledText(frame)
            self.console.configure(font='TkFixedFont')
            self.console.pack(padx=10, pady=10, fill=BOTH, expand=True)
            self.log_queue = queue
            # Start polling messages from the queue
            self.frame.after(100, self.poll_log_queue)
    
        def display(self, msg):
            self.console.configure(state='normal')
            self.console.insert(END, msg + '\n')
            self.console.configure(state='disabled')
            # Autoscroll to the bottom
            self.console.yview(END)
    
        def poll_log_queue(self):
            # Check every 100ms if there is a new message in the queue to display
            while not self.log_queue.empty():
                msg = self.log_queue.get(block=False)
                self.display(msg)
            self.frame.after(100, self.poll_log_queue)
    
    

    As result a widget displays all logging data of an app.

提交回复
热议问题