Я использую модуль в своем приложении python, который записывает много сообщений с помощью модуля регистрации. Первоначально я использовал это в консольном приложении, и было довольно легко получить вывод журнала для отображения на консоли с помощью обработчика консоли. Теперь я разработал GUI-версию моего приложения с помощью wxPython, и я бы хотел отобразить весь вывод журнала в пользовательский элемент управления - многострочный textCtrl. Есть ли способ создать собственный обработчик ведения журнала, чтобы я мог перенаправлять все выходные данные журнала и отображать сообщения о регистрации везде, где бы я ни захотел - в этом случае - приложение wxPython.
Как перенаправить регистратор на wxPython textCtrl с помощью специального обработчика ведения журнала?
Ответ 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()
Скриншот:
Обновление:. Как отмечает 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
.