Запуск Python-скрипта в потоке и перенаправление std.out / std.err в wx.TextCtrl в графическом интерфейсе - PullRequest
3 голосов
/ 24 августа 2010

Я пытаюсь написать GUI, который читает настройки в python-скрипте, затем генерирует скрипт и запускает его. Выполнение сценария может занять десятки минут, чтобы не блокировать графический интерфейс и не расстраивать пользователя, я запускаю его в отдельном потоке. Перед этим я использовал отдельный класс для перенаправления std.out и std.err программы в TextCtrl. Это работало нормально, за исключением того, что 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

Я безуспешно пытался использовать какой-то класс связи из потока в графический интерфейс. То есть графический интерфейс по-прежнему блокируется.

У кого-нибудь есть подсказки или решение этой проблемы, то есть вывести stdout / err из сценария в графический интерфейс без блокировки графического интерфейса?

Ответы [ 2 ]

2 голосов
/ 28 сентября 2010

Еще одним решением, которое я использовал с успехом, было бы использование регистрации в python вместо 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)
2 голосов
/ 24 августа 2010

Да.Из потока используйте wx.CallAfter, чтобы отправить текст в графический интерфейс потокобезопасным способом.Затем он может взять текст и отобразить его.Другой способ сделать это - использовать подпроцесс и общаться с ним.Вот пример этого:

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/

К сожалению, моя система комментирования в то время не справлялась с отступами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...