2010-05-12 16 views
11

Python uygulamasında, günlüğe kaydetme modülünü kullanarak çok sayıda ileti yazan bir modül kullanıyorum. Başlangıçta bunu bir konsol uygulamasında kullanıyordum ve konsol işleyicisi kullanarak konsolda görüntülemek için günlüğe kaydetme çıktısını almak oldukça kolaydı. Şimdi wxPython kullanarak uygulamasının bir GUI sürümünü geliştirdim ve tüm kayıt çıktısını özel bir denetime - çok satırlı bir textCtrl - görüntülemek istiyorum. Özel bir günlüğe kaydetme işleyicisi oluşturabilmemin bir yolu var, böylece tüm günlüğe kaydetme çıktısını orada yeniden yönlendirebilirim ve/veya istediğim yerde günlüğe kaydetme mesajlarını görüntüleyebilirim - bu durumda bir wxPython uygulaması.Kaydediciyi özel bir günlüğe kaydetme işleyicisi kullanarak bir wxPython textCtrl dosyasına nasıl yeniden yönlendirebilirim?

cevap

12

kontrolünüz Sonra

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) 

işleyicisi oluştur

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() 
+0

@Vinjay Sajip: Wx ana döngüsünün dışında olaylar kaydedilmişse cevabınız iş parçacığı güvenli değildir. Dış iş parçacıklarından veri işlemek için wx olaylarını kullanmak daha güvenlidir. – iondiode

+0

Şüphesiz haklısınız, ama cevabım, sadece savaşta test edilmiş bir çözüm sunmaktan ziyade kullanılacak yaklaşımı işaret ediyor. –

3

Özel bir logging.Handler oluşturmanız ve logging.Logger ürününüze eklemeniz gerekecek. belgelerine

:

Handler nesneler işleyicisi'nın belirtilen hedefe (günlük mesajlarının şiddetine göre) uygun günlük mesajlar gönderilmesi sorumludur. Logger nesneleri, bir addHandler() yöntemiyle sıfır veya daha fazla işleyici nesnesini yöntemine ekleyebilir. Örnek bir senaryo olarak, bir uygulaması, tüm günlük uygulamalarının bir günlük dosyasına, tüm günlük hata iletilerine veya daha yüksek iletilere, ve tüm önemli iletileri bir e-posta adresine göndermek isteyebilir. Bu senaryoda, her bir işleyicisinin işleyicisinin, belirli bir önem derecesine sahip iletilerinin belirli bir konuma belirli bir konuma gönderilmesinden sorumlu olduğu üç ayrı işleyici gerekir.

Handler API için http://docs.python.org/library/logging.html#handler-objects'a bakın.

Özellikle, çıktı hedefini belirlemek için uygulayabileceğiniz Handler.emit(record) yöntemidir. Muhtemelen, bunu TextCtrl.AppendText'u aramak için uygularsınız.

4

Burada basit çalışma örnek:

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() 

Ekran Görüntüsü:

Screenshot of running script

Güncelleme: iondiode işaret ettiği gibi uygulamanızda birden evre varsa, bu basit script tüm böyle bir işleyici yoluyla oturum, sorunlar olabilir; İdeal olarak sadece bir UI iş parçacığı UI'yi güncellemelidir. Etkinliğin günlüğe kaydedilmesi için önerilen yaklaşımı, yanıtına göre özel bir etkinlik kullanarak kullanabilirsiniz.

+0

, satır günlüğü oluyor.Handler .__ init __ (self) doğru mu?__init__ içinde kendini geçmek doğru mu? – piertoni