Подтвердить что ты не робот

Как перенаправить регистратор на wxPython textCtrl с помощью специального обработчика ведения журнала?

Я использую модуль в своем приложении python, который записывает много сообщений с помощью модуля регистрации. Первоначально я использовал это в консольном приложении, и было довольно легко получить вывод журнала для отображения на консоли с помощью обработчика консоли. Теперь я разработал GUI-версию моего приложения с помощью wxPython, и я бы хотел отобразить весь вывод журнала в пользовательский элемент управления - многострочный textCtrl. Есть ли способ создать собственный обработчик ведения журнала, чтобы я мог перенаправлять все выходные данные журнала и отображать сообщения о регистрации везде, где бы я ни захотел - в этом случае - приложение wxPython.

4b9b3361

Ответ 1

Создать обработчик

import wx
import wx.lib.newevent

import logging

# create event type
wxLogEvent, EVT_WX_LOG_EVENT = wx.lib.newevent.NewEvent()


class wxLogHandler(logging.Handler):
    """
    A handler class which sends log strings to a wx object
    """
    def __init__(self, wxDest=None):
        """
        Initialize the handler
        @param wxDest: the destination object to post the event to 
        @type wxDest: wx.Window
        """
        logging.Handler.__init__(self)
        self.wxDest = wxDest
        self.level = logging.DEBUG

    def flush(self):
        """
        does nothing for this handler
        """


    def emit(self, record):
        """
        Emit a record.

        """
        try:
            msg = self.format(record)
            evt = wxLogEvent(message=msg,levelname=record.levelname)            
            wx.PostEvent(self.wxDest,evt)
        except (KeyboardInterrupt, SystemExit):
            raise
        except:
            self.handleError(record)

Затем в вашем управлении

self.Bind(EVT_WX_LOG_EVENT, self.onLogEvent)

def onLogEvent(self,event):
    '''
    Add event.message to text window
    '''
    msg = event.message.strip("\r")+"\n"
    self.logwindow.AppendText(msg) # or whatevery
    event.Skip()

Ответ 2

Вот простой рабочий пример:

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 of running script

Обновление:. Как отмечает iondiode, этот простой script может иметь проблемы, если в приложении есть несколько потоков, все протоколируются через такой обработчик; в идеале только пользовательский интерфейс должен обновлять пользовательский интерфейс. Вы можете использовать предложенный подход для регистрации события, используя пользовательское событие в соответствии с его ответом.

Ответ 3

Вам нужно будет создать пользовательский logging.Handler и добавить его в logging.Logger.

Из документации:

Объекты

Handler несут ответственность за отправка соответствующего журнала сообщений (на основе сообщений журнала серьезность) указанным обработчикам место назначения. Объекты Logger могут добавлять ноль или больше объектов обработчика сами с addHandler() метод. В качестве примерного сценария приложение может захотеть отправить весь журнал сообщения в файл журнала, весь журнал сообщения об ошибках или выше в stdout, и все сообщения, имеющие решающее значение для адрес электронной почты. Этот сценарий требует три отдельных обработчика, где каждый обработчик отвечает за отправку сообщения определенной степени тяжести конкретное местоположение.

Смотрите http://docs.python.org/library/logging.html#handler-objects для API Handler.

В частности, это метод Handler.emit(record), который вы можете реализовать, чтобы указать назначение вывода. Предположительно, вы выполнили бы это, чтобы вызвать TextCtrl.AppendText.