2010-05-12 10 views
11

मैं अपने अजगर अनुप्रयोग में एक मॉड्यूल है कि एक प्रवेश मॉड्यूल का उपयोग कर संदेशों का एक बहुत लिखते उपयोग कर रहा हूँ। प्रारंभ में मैं इसे कंसोल एप्लिकेशन में उपयोग कर रहा था और कंसोल हैंडलर का उपयोग कर कंसोल पर लॉगिंग आउटपुट को प्रदर्शित करना बहुत आसान था। अब मैंने wxPython का उपयोग करके अपने ऐप का एक जीयूआई संस्करण विकसित किया है और मैं सभी लॉगिंग आउटपुट को कस्टम नियंत्रण में प्रदर्शित करना चाहता हूं - एक बहु-पंक्ति textCtrl। इस मामले में, एक wxPython अनुप्रयोग में - वहाँ एक रास्ता मैं तो मैं सब लॉगिंग उत्पादन वहाँ अनुप्रेषित और लॉगिंग संदेश प्रदर्शित जहाँ भी/लेकिन मैं चाहता हूँ कर सकते हैं एक कस्टम प्रवेश हैंडलर बना सकते है।मैं एक कस्टम प्रवेश हैंडलर का उपयोग कर एक wxPython textCtrl को लकड़हारा कैसे अनुप्रेषित कर सकते हैं?

उत्तर

12

आपके नियंत्रण में हैंडलर

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

@ विंजय साजिप: यदि आपका शब्द wx मुख्य पाश के बाहर लॉग इन है तो आपका उत्तर थ्रेड सुरक्षित नहीं है। बाहरी धागे से डेटा को संसाधित करने के लिए Wx घटनाओं का उपयोग करना सुरक्षित है। – iondiode

+0

इसमें कोई संदेह नहीं है कि आप सही हैं, लेकिन मेरा जवाब पूरी तरह से युद्ध-परीक्षण समाधान की पेशकश के बजाय उपयोग किए जाने वाले दृष्टिकोण को इंगित करता है। –

3

आप एक कस्टम logging.Handler बनाते हैं और अपने logging.Logger में जोड़ने के लिए की आवश्यकता होगी।

प्रलेखन से:

Handler वस्तुओं हैंडलर के निर्दिष्ट गंतव्य के लिए उचित लॉग संदेश (लॉग संदेश ' गंभीरता के आधार पर) भेजने लिए जिम्मेदार हैं। लकड़हारा वस्तुओं एक addHandler() विधि के साथ खुद को को शून्य या अधिक हैंडलर वस्तुओं जोड़ सकते हैं। एक उदाहरण परिदृश्य के रूप में, एप्लिकेशन सभी लॉग संदेशों को लॉग फ़ाइल में भेजना चाह सकता है, सभी लॉग त्रुटि या उच्चतर संदेशों को stdout, और ईमेल पते के लिए महत्वपूर्ण सभी संदेश भेजना चाहते हैं। इस परिदृश्य तीन अलग-अलग संचालकों जहां प्रत्येक हैंडलर एक विशिष्ट स्थान के लिए एक विशिष्ट गंभीरता के संदेश भेजने के लिए जिम्मेदार है की आवश्यकता है।

Handler एपीआई के लिए http://docs.python.org/library/logging.html#handler-objects देखें।

विशेष रूप से, यह Handler.emit(record) विधि है जिसे आप आउटपुट के गंतव्य निर्दिष्ट करने के लिए कार्यान्वित कर सकते हैं। संभवतः, आप TextCtrl.AppendText पर कॉल करने के लिए इसे लागू करेंगे।

4

यहाँ एक सरल काम कर उदाहरण है:

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

अद्यतन: आयनोडीड बताते हैं, इस सरल स्क्रिप्ट में समस्या हो सकती है यदि आपके ऐप में कई थ्रेड हैं, तो सभी हैंडलर के माध्यम से लॉगिंग; आदर्श रूप से केवल यूआई थ्रेड को यूआई अपडेट करना चाहिए। आप अपने उत्तर के अनुसार, कस्टम ईवेंट का उपयोग करके ईवेंट लॉगिंग के सुझाए गए दृष्टिकोण का उपयोग कर सकते हैं।

+0

लाइन लॉगिंग है। हैंडलर .__ init __ (स्वयं) सही है?क्या यह __init__ के अंदर स्वयं को पारित करने का अधिकार है? – piertoni

संबंधित मुद्दे