为什么 QDialog 中发出的信号不能调用 QThread 中连接的插槽?

why signal emitting in QDialog can not invoke the connected slot in QThread?

这是我的代码:

from PySide import QtCore, QtGui
import sys
import time

class TestThread(QtCore.QThread):

    def __init__(self):
        self.finished_flag = False
        super(TestThread, self).__init__()

    def finished(self):
        print('==========finished function is invoked!=======================')
        self.finished_flag = True

    def run(self):
        while(True): 
            print('thread is running...') 
            time.sleep(1)            
            if self.finished_flag:
                print('thread exist!')
                break


class TestDialog(QtGui.QDialog):
    ForceTermimateSignal = QtCore.Signal()

    def done(self, code):
        print('================dialog done!==================')
        self.ForceTermimateSignal.emit()
        super(TestDialog, self).done(code)


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)

    dlg = TestDialog()
    testThread = TestThread()

    dlg.ForceTermimateSignal.connect(testThread.finished)

    testThread.start()

    dlg.exec_()

    if testThread.isFinished():
        print('thread finished')
    else:
        print('thread is still running!')
        testThread.wait()

这是运行以上代码然后关闭对话框的结果:

thread is running...
thread is running...
thread is running...
thread is running...
================dialog done!==================
thread is still running!
thread is running...
thread is running...
thread is running...

所以我想知道:为什么dlg发出的ForceTermimateSignal不能调用对象testThread的'finished'函数?

当你在同一个线程中将一个信号连接到一个槽时,槽将被直接同步调用。但是当连接是跨线程的时候,信号会作为事件发布,槽会被异步调用。

因此在您的示例中,这一行:

    self.ForceTermimateSignal.emit()

将向对话框的事件队列添加信号事件,然后 return 不直接调用线程的 finished 槽。下面一行:

    super(TestDialog, self).done(code)

然后将立即执行,这将在信号事件有机会被处理之前终止事件循环。

如果将发射线替​​换为:

   testThread.finished_flag = True

该示例应按预期工作。

受@ekhumoro的启发,我参考了QT文档Signals and Slots Across Threads,发现QT中有很多不同的连接类型。了解了这些类型,一切就清楚了。

替换上面的代码:

dlg.ForceTermimateSignal.connect(testThread.finished)

与:

dlg.ForceTermimateSignal.connect(teshThread.finished, type=Qt.DirectConnection)

然后,一切正常。