为什么 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)
然后,一切正常。
这是我的代码:
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)
然后,一切正常。