![](/img/trans.png)
[英]Why doesn't the QThread object have a finished signal when creating a worker QObject?
[英]QThread.finished signal isn't emitted after worker finishes
我有以下代碼:
import time
from PyQt5.QtCore import QThread, QObject
from PyQt5.QtWidgets import QWidget, QApplication
class Worker(QObject):
def run(self):
time.sleep(1)
print("Worker is finished")
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.show()
self.thread = QThread()
self.worker = Worker()
self.worker.moveToThread(self.thread)
self.thread.started.connect(self.worker.run)
self.thread.finished.connect(self.on_thread_finished)
self.thread.start()
def on_thread_finished(self):
print("Thread finished")
self.thread.deleteLater()
if __name__ == "__main__":
app = QApplication([])
window = MainWindow()
app.exec_()
運行它,它顯示窗口,打印Worker is finished
,僅此而已。 這很奇怪。 恕我直言,當工人完成時,線程也應該完成,這意味着應該調用on_thread_finished
方法並打印Thread finished
。 但事實並非如此。 為什么?
當您使用moveToThread
而不是重新實現QThread.run時,線程將啟動自己的事件循環,該循環將等待直到顯式調用exit/quit
。 finished
信號僅在事件循環停止后(和/或run
返回)發出。 處理這種情況的常用方法是從 worker 發出自定義信號,並將其連接到線程的quit
槽。 (注意:跨線程信號槽連接保證是線程安全的)。
因此,您的示例將通過以下更改按預期工作:
class Worker(QObject):
finished = QtCore.pyqtSignal()
def run(self):
time.sleep(1)
print("Worker is finished")
self.finished.emit()
class MainWindow(QWidget):
def __init__(self):
...
self.worker.moveToThread(self.thread)
self.worker.finished.connect(self.thread.quit)
當工人完成時,線程也應該完成
這不是它的工作原理。 您的Worker::run
方法通過通常的signal
/ slot
機制作為slot
調用,之后QThread
將繼續正常處理事件。
如果你想在Worker::run
完成時終止QThread
,你需要明確告訴它這樣做......
import time
from PyQt5.QtCore import Qt, QThread, QObject
from PyQt5.QtWidgets import QWidget, QApplication
class Worker(QObject):
# Constructor accepts the QThread as a parameter and stashes it
# for later use.
def __init__(self, thread):
super(Worker, self).__init__()
self.m_thread = thread
def run(self):
time.sleep(1)
print("Worker is finished")
# We're done so ask the `QThread` to terminate.
if self.m_thread:
self.m_thread.quit()
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.show()
self.thread = QThread()
# Pass the QThread to the Worker's ctor.
self.worker = Worker(self.thread)
self.worker.moveToThread(self.thread)
self.thread.started.connect(self.worker.run)
self.thread.finished.connect(self.on_thread_finished)
self.thread.start()
def on_thread_finished(self):
print("Thread finished")
self.thread.deleteLater()
if __name__ == "__main__":
app = QApplication([])
window = MainWindow()
app.exec_()
非常“不雅”,但它傳達了這個想法。
一個更簡單的替代方案是簡單地使用QThread::currentThread()
,在這種情況下,您的Worker::run
方法變為......
class Worker(QObject):
def run(self):
time.sleep(1)
print("Worker is finished")
# We're done so ask the `QThread` to terminate.
QThread.currentThread().quit()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.