【问题标题】:Emit signal in standard python thread在标准 python 线程中发出信号
【发布时间】:2013-10-05 08:57:58
【问题描述】:

我有一个线程应用程序,其中有一个网络线程。 UI 部分将callback 传递给该线程。该线程是 普通 python 线程 - NO QThread

是否可以在这个线程中发出 PyQT Slot?

【问题讨论】:

    标签: python pyqt signals-slots


    【解决方案1】:

    不,不可能像这样从 python 线程发出 PyQt 信号。

    但是,一种可能的解决方案是使用由 两个线程,进行必要的操作以最终发出线程安全的 PyQt 信号。

    这是一个“SafeConnector”类的实现,使用了一对 连接的套接字和一个队列在两个线程之间交换数据, 并使用 QSocketNotifier 回到 Qt 的循环中。 QObject 用于 使发出正确的 Qt 信号成为可能:

    from PyQt4 import Qt, QtCore, QtGui
    import threading
    import socket
    import Queue
    import time
    
    # Object of this class has to be shared between
    # the two threads (Python and Qt one).
    # Qt thread calls 'connect',   
    # Python thread calls 'emit'.
    # The slot corresponding to the emitted signal
    # will be called in Qt's thread.
    class SafeConnector:
        def __init__(self):
            self._rsock, self._wsock = socket.socketpair()
            self._queue = Queue.Queue()
            self._qt_object = QtCore.QObject()
            self._notifier = QtCore.QSocketNotifier(self._rsock.fileno(),
                                                    QtCore.QSocketNotifier.Read)
            self._notifier.activated.connect(self._recv)
    
        def connect(self, signal, receiver):
            QtCore.QObject.connect(self._qt_object, signal, receiver)
    
        # should be called by Python thread
        def emit(self, signal, args):
            self._queue.put((signal, args))
            self._wsock.send('!')
    
        # happens in Qt's main thread
        def _recv(self):
            self._rsock.recv(1)
            signal, args = self._queue.get()
            self._qt_object.emit(signal, args)
    
    class PythonThread(threading.Thread):
        def __init__(self, connector, *args, **kwargs):
            threading.Thread.__init__(self, *args, **kwargs)
            self.connector = connector
            self.daemon = True
    
        def emit_signal(self):
            self.connector.emit(QtCore.SIGNAL("test"), str(time.time()))
    
        def run(self):
            while True:
                time.sleep(1)
                self.emit_signal()
    
    if __name__ == '__main__':
        app = QtGui.QApplication([])
        mainwin = QtGui.QMainWindow()
        label = QtGui.QLabel(mainwin)
        mainwin.setCentralWidget(label)
    
        connector = SafeConnector()
        python_thread = PythonThread(connector)
        connector.connect(QtCore.SIGNAL("test"), label.setText)
        python_thread.start()
    
        mainwin.show()
        app.exec_()
    

    【讨论】:

    • 干得好,虽然需要很多代码。
    • def emit(self, signal, args): args 应该是 *args
    • 在 PyQt5 上,qobject_living_in_main_thread.some_signal.emit() 信号从我的 Ubuntu 机器上的后台 Python 线程(不是 QThread)工作(没有警告,没有崩溃,插槽在接收器的 [主] 线程中正常调用)。我没有在文档中找到保证行为的地方。谷歌把我带到了这里。
    猜你喜欢
    • 2015-08-20
    • 2018-01-15
    • 1970-01-01
    • 2010-10-12
    • 2014-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多