在标准 Python 线程中发射信号

7

我有一个线程应用程序,其中包含一个网络线程。UI部分将回调函数传递给此线程。该线程是一个普通的Python线程 - 不是QThread

在此线程中是否可以触发PyQT Slot?

1个回答

7
不,无法通过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_()

干得好,虽然需要很多代码。 - Trilarion
def emit(self, signal, args): args 应该是 *args - user3722836
1
在PyQt5中,qobject_living_in_main_thread.some_signal.emit()信号可以从后台Python线程(不是QThread)中工作,在我的Ubuntu机器上没有警告、没有崩溃,在接收者的[主要]线程中正常调用槽函数。我还没有在文档中找到这种行为的保证。Google 把我带到了这里。 - jfs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接