How can I redirect the logger to a wxPython textCtrl using a custom logging handler?

后端 未结 3 708
灰色年华
灰色年华 2020-12-28 20:53

I\'m using a module in my python app that writes a lot a of messages using the logging module. Initially I was using this in a console application and it was pretty easy to

3条回答
  •  醉话见心
    2020-12-28 21:50

    Here's a simple working example:

    import logging
    import random
    import sys
    import wx
    
    logger = logging.getLogger(__name__)
    
    class WxTextCtrlHandler(logging.Handler):
        def __init__(self, ctrl):
            logging.Handler.__init__(self)
            self.ctrl = ctrl
    
        def emit(self, record):
            s = self.format(record) + '\n'
            wx.CallAfter(self.ctrl.WriteText, s)
    
    LEVELS = [
        logging.DEBUG,
        logging.INFO,
        logging.WARNING,
        logging.ERROR,
        logging.CRITICAL
    ]
    
    class Frame(wx.Frame):
    
        def __init__(self):
            TITLE = "wxPython Logging To A Control"
            wx.Frame.__init__(self, None, wx.ID_ANY, TITLE)
    
            panel = wx.Panel(self, wx.ID_ANY)
            log = wx.TextCtrl(panel, wx.ID_ANY, size=(300,100),
                              style = wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL)
            btn = wx.Button(panel, wx.ID_ANY, 'Log something!')
            self.Bind(wx.EVT_BUTTON, self.onButton, btn)
    
            sizer = wx.BoxSizer(wx.VERTICAL)
            sizer.Add(log, 1, wx.ALL|wx.EXPAND, 5)
            sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5)
            panel.SetSizer(sizer)
            handler = WxTextCtrlHandler(log)
            logger.addHandler(handler)
            FORMAT = "%(asctime)s %(levelname)s %(message)s"
            handler.setFormatter(logging.Formatter(FORMAT))
            logger.setLevel(logging.DEBUG)
    
        def onButton(self, event):
            logger.log(random.choice(LEVELS), "More? click again!")
    
    if __name__ == "__main__":
        app = wx.PySimpleApp()
        frame = Frame().Show()
        app.MainLoop()
    

    Screenshot:

    Screenshot of running script

    Update: As iondiode points out, this simple script may have problems if there are multiple threads in your app, all logging via such a handler; ideally only a UI thread should update the UI. You can use the suggested approach of logging the event by using a custom event, as per his answer.

提交回复
热议问题