Python PySide中未处理信号

Python PySide中未处理信号,python,multithreading,qt,pyside,Python,Multithreading,Qt,Pyside,我有一个PySide应用程序。在此应用程序中,主函数在线程中运行(AnalysisThread)。在这个线程中,我用python记录器记录了一些东西。然后我添加了一个定制的记录器,它本质上是用字符串触发一个信号。这个信号可以在主线程(GUI线程)中处理,但很明显插槽从未被触发,但我确信调用了signalself.messagewrite.emit函数(调试器确认了这一点)。我做错了什么 class LogStream(QtCore.QObject): messageWritten = Q

我有一个PySide应用程序。在此应用程序中,主函数在线程中运行(
AnalysisThread
)。在这个线程中,我用python记录器记录了一些东西。然后我添加了一个定制的记录器,它本质上是用字符串触发一个信号。这个信号可以在主线程(GUI线程)中处理,但很明显插槽从未被触发,但我确信调用了signal
self.messagewrite.emit
函数(调试器确认了这一点)。我做错了什么

class LogStream(QtCore.QObject):
    messageWritten = QtCore.Signal(str)
    signal_test = QtCore.Signal()

    def write(self, msg):
        if not self.signalsBlocked():
            self.messageWritten.emit(msg)


class QtHandler(logging.Handler):
    def __init__(self, stream):
        logging.Handler.__init__(self)
        self.stream = stream

    def emit(self, record):
        record = self.format(record)
        if record:
            self.stream.write('%s\n' % record)

class AnalysisThread(QtCore.QThread):
    processing_ended = QtCore.Signal()
    processing_failed = QtCore.Signal(Exception, list)

    def __init__(self, analysis):
        super(AnalysisThread, self).__init__()
        self.analysis = analysis

    def run(self):
        try:
            process = Process(target=self.analysis.analyze)
            process.start()
            process.join()
        except Exception as err:
            exec_info = sys.exc_info()
            self.processing_failed.emit(err, exec_info)
        finally:
            self.processing_ended.emit()

class ProcessView(QtGui.QMainWindow):

    def __init__(self):
        super(ProcessView, self).__init__()
        # Log Stream
        self.stream = LogStream()
        self.stream.messageWritten.connect(self.on_log_written)

    def go(self):
        analysis = MyAnalysis()
        # Handler
        handler = QtHandler(self.stream)
        handler.setFormatter(logging.Formatter('(%(levelname)s-%(name)s)  %(message)s'))
        analysis.log.addHandler(handler)
        self.processing = AnalysisThread(analysis)
        self.processing.processing_ended.connect(self.on_processing_ended)

 self.processing.processing_failed.connect(self.on_processing_failed)
        self.processing.start()

    def on_log_written(self, msg):
        print('Message: {}'.format(msg))  # never called
编辑


为了澄清,它是一个多线程应用程序,但也是一个多进程应用程序…

由于您在多线程环境中工作,请在连接信号和插槽时尝试指定Qt.QueuedConnection

例如:

self.stream.messageWritten.connect(self.on_log_written, QtCore.Qt.QueuedConnection)

回答

我终于找到了解决办法。如前所述,我的应用程序使用多处理,并且日志发生在子进程中,因此父进程永远不会对信号发出警报。解决方案是使用
多处理.Pipe
在子进程和父进程之间创建“链接”。一个实现可以是

class Streamer(QtCore.QThread):
    messageWritten = QtCore.Signal(str)

    def __init__(self, pipe):
        super(Streamer, self).__init__()
        self.pipe = pipe

    def run(self):
        while True:
            try:
                msg = self.pipe.recv()
            except EOFError:
                break
            else:
                self.messageWritten.emit(msg)

class QtHandler(logging.Handler):
    def __init__(self, stream):
        """Instantiate handler

        :param stream: multiprocessing.Pipe
        """
        logging.Handler.__init__(self)
        self.stream = stream

    def emit(self, record):
        record = self.format(record)
        if record:
            self.stream.send('%s\n' % record)

class ProcessView(QtGui.QMainWindow):

    def __init__(self):
        super(ProcessView, self).__init__()
        # Log Stream
        mother_pipe, child_pipe = Pipe()
        self.stream = child_pipe
        self.streamer = Streamer(mother_pipe)
        self.streamer.daemon = True
        self.streamer.start()
        self.streamer.messageWritten.connect(self.on_log_written)

    def on_log_written(self, msg):
        self.ui.textBrowser_log.insertPlainText(msg)
        txt_max = self.ui.textBrowser_log.verticalScrollBar().maximum()
        self.ui.textBrowser_log.verticalScrollBar().setValue(txt_max)
说明:


主线程(GUI)启动。在初始化时,它创建一个
多进程.Pipe
与子进程通信,以及一个监听管道末端的守护进程。因此,在启动子进程之后,它最终会记录一些内容。
QtHandler
截取消息并通过管道发送。守护进程在管道的另一端接收消息,并通过信号
messagewrited
将其转发给GUI线程。最后,该信号由一个插槽处理,该插槽将其写入
QTextBrowser
,根据文档,滚动条被刷新到,队列连接是多线程的默认行为。但是,它不起作用,DirectConnection也不起作用。即使在执行结束时,也不会显示日志。