2010-08-24 96 views
3

我試圖編寫一個讀取python腳本設置的GUI,然後生成腳本並運行它。該腳本可能需要幾十分鐘才能運行,所以爲了不阻止GUI並阻止用戶在單獨的線程中運行它。在我這樣做之前,我使用一個單獨的類將程序的std.out和std.err重定向到TextCtrl。除了GUI在執行期間被阻塞之外,這工作正常。在線程中運行Python腳本並將std.out/std.err重定向到GUI中的wx.TextCtrl

使用重定向類從線程運行腳本仍會阻止GUI。爲了不阻止GUI,我需要關閉重定向。來自腳本和gui的所有std.out/err然後進入控制檯。

這裏是重定向的類以及我怎麼稱呼它。

# For redirecting stdout/stderr to txtctrl. 
class RedirectText(object): 
    def __init__(self,aWxTextCtrl): 
     self.out=aWxTextCtrl 

    def write(self,string): 
     self.out.WriteText(string) 

self.redir=RedirectText(self.bottom_text) 
sys.stdout=self.redir 
sys.stderr=self.redir 
sys.stdin=self.redir 

我試過使用某種通信類從線程到GUI沒有成功。也就是說,GUI仍然被阻止。

有沒有人有這個問題的一些提示或解決方案,即從腳本到GUI的stdout/err沒有阻止GUI?

回答

2

是的。在線程中,使用wx.CallAfter將文本發送到GUI以線程安全的方式。然後它可以獲取文本並顯示它。另一種做法是使用子進程並與之通信。這裏有這樣一個例子:

http://www.blog.pythonlibrary.org/2010/06/05/python-running-ping-traceroute-and-more/

也有這篇文章的註釋中列出一些方法:

http://www.blog.pythonlibrary.org/2009/01/01/wxpython-redirecting-stdout-stderr/

不幸的是,我當時的評論系統沒有做縮進的好工作。

2

我成功使用的另一個解決方案是使用python logging而不是stdout/stderr。爲了做到這一點,你寫一個擴展logging.Handler一個子類,可自定義字體和文本顏色在wx.TextCtrl在WX應用呈現:

import logging 
from logging import Handler 

class WxHandler(Handler): 
    def __init__(self, logCtrl): 
     """ 
     Initialize the handler. 
     logCtrl = an instance of wx.TextCtrl 
     """ 
     self.logCtrl = logCtrl 
     Handler.__init__(self) 

    def flush(self): 
     pass 

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

     If a formatter is specified, it is used to format the record. 
     The record is then written to the stream with a trailing newline. If 
     exception information is present, it is formatted using 
     traceback.print_exception and appended to the stream. If the stream 
     has an 'encoding' attribute, it is used to encode the message before 
     output to the stream. 
     """ 
     try: 
      lastPos = self.logCtrl.GetLastPosition() 
      msg = self.format(record) 
      self.logCtrl.WriteText(msg) 
      self.logCtrl.WriteText('\r\n') 
      f = wx.Font(10, wx.MODERN, wx.NORMAL, wx.NORMAL, False, u'Arial', wx.FONTENCODING_ISO8859_1) 
      if record.levelno == logging.INFO: 
       textColour = wx.Colour(0, 0, 205) 
      elif record.levelno == logging.WARN: 
       textColour = wx.Colour(250, 128, 114) 
      elif record.levelno >= logging.ERROR: 
       textColour = wx.Colour(220, 20, 60) 
      else: 
       textColour = wx.Colour(0, 0, 0) 
      self.logCtrl.SetStyle(lastPos, lastPos + len(msg), wx.TextAttr(textColour, wx.NullColour, f)) 
     except: 
      self.handleError(record) 

爲了配置記錄器:

def configureWxLogger(logCtrl, loggingLevel): 
    """ 
     Wx Logger config 
    """ 
    logger = logging.getLogger() 
    logger.setLevel(loggingLevel) 
    ch = WxHandler(logCtrl) 
    formatter = logging.Formatter("%(asctime)-20s - %(levelname)-8s - %(message)s") 
    formatter.datefmt = '%d/%m/%Y-%H:%M:%S' 
    ch.setFormatter(formatter) 
    logger.addHandler(ch) 
    return logger 

最後,綁定文本控件的日誌輸出:

self.logCtrl = wx.TextCtrl(self, -1, "", size=(600, 200), style=wx.TE_MULTILINE|wx.TE_RICH2) 
wxLoggingHelper.configureWxLogger(self.logCtrl, logging.DEBUG)