在将 Worker 对象移动到 pyqt 中的 QThread 之前设置信号和槽
Setup signal and slot before moving Worker object to QThread in pyqt
在 Qt/PyQt 中,我曾经使用 Worker class 和 QThread 创建线程。
self.worker = Worker()
self.thread = QThread()
worker.moveToThread(thread)
setup_signal_slot_with_main_object()
// start
thread.start()
我必须在 moveToThread() 之后放置 setup_signal_slot_with_main_object()。但是我有一个复杂的工人。在Worker.__ init__()中,它创建了许多QObjects并连接内部信号和槽。我不想创建一个在 worker->moveToThread(&thread) 之后建立所有连接和调用 worker.setup_signal_slot() 的方法因为 Worker 包含许多子 QObject,并且每个 QObject 都可以在其构造函数中创建 signal/slot。
在 Qt/C++ 中,我可以在 worker 的构造函数中建立 signal/slot 连接。但是在 PyQt 中,插槽不会 运行 在新线程中。
这是一个 Worker 包含 QTimer 的示例
import sys
import signal
import threading
from PyQt5.QtCore import QObject, pyqtSignal, QTimer, QCoreApplication, QThread
import datetime
class Worker(QObject):
timeChanged = pyqtSignal(object)
def __init__(self, parent=None):
QObject.__init__(self, parent)
self.timer = QTimer(self)
self.timer.setInterval(1000)
# I want to make connection at here
self.timer.timeout.connect(self.main_process)
def start(self):
# self.timer.timeout.connect(self.main_process)
self.timer.start()
print('Worker thread {}: Start timer'.format(threading.get_ident()))
# this method still run in main thread
def main_process(self):
timestamp = datetime.datetime.now()
print('Worker thread {}: {}'.format(threading.get_ident(), timestamp.strftime('%d-%m-%Y %H-%M-%S')))
self.timeChanged.emit(timestamp)
class WorkerThread(QObject):
def __init__(self, parent=None):
QObject.__init__(self, parent)
self.emitter = Worker()
self.thread = QThread(self)
self.emitter.moveToThread(self.thread)
self.thread.started.connect(self.emitter.start)
self.thread.finished.connect(self.emitter.deleteLater)
self.emitter.timeChanged.connect(self.show_time)
def start(self):
self.thread.start()
def stop(self):
if self.thread.isRunning():
self.thread.quit()
self.thread.wait()
print('Exit thread')
def show_time(self, timestamp):
print('Main thread {}: {}'.format(threading.get_ident(), timestamp.strftime('%d-%m-%Y %H-%M-%S')))
def signal_handler(sig, frame):
print('Quit')
app.quit()
if __name__ == '__main__':
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
app = QCoreApplication(sys.argv)
timer = QTimer()
timer.timeout.connect(lambda: None)
timer.start(500)
print('Main thread {}'.format(threading.get_ident()))
emitter = WorkerThread()
emitter.start()
sys.exit(app.exec_())
在Worker中,定时器超时会在主线程中调用main_process。我可以将 self.timer.timeout.connect(self.main_process) 移动到方法 worker.start() 中。但是正如我上面所说,我仍然想在它的构造函数中放置 internal signal/slot 。
谁能建议我一个解决方案?谢谢!
如果您希望在接收方使用 pyqtSlot()
装饰器的同一线程中调用这些方法,如果您不这样做,那么它将在发送方的线程中调用。
import sys
import signal
import threading
import datetime
from PyQt5.QtCore import QObject, pyqtSignal, QTimer, QCoreApplication, QThread, pyqtSlot
class Worker(QObject):
timeChanged = pyqtSignal(object)
def __init__(self, parent=None):
QObject.__init__(self, parent)
self.timer = QTimer(self)
self.timer.setInterval(1000)
self.timer.timeout.connect(self.main_process)
@pyqtSlot()
def start(self):
self.timer.start()
print("Worker thread {}: Start timer".format(threading.get_ident()))
@pyqtSlot()
def main_process(self):
timestamp = datetime.datetime.now()
print(
"Worker thread {}: {}".format(
threading.get_ident(), timestamp.strftime("%d-%m-%Y %H-%M-%S")
)
)
self.timeChanged.emit(timestamp)
class WorkerThread(QObject):
def __init__(self, parent=None):
QObject.__init__(self, parent)
self.emitter = Worker()
self.thread = QThread(self)
self.emitter.moveToThread(self.thread)
self.thread.started.connect(self.emitter.start)
self.thread.finished.connect(self.emitter.deleteLater)
self.emitter.timeChanged.connect(self.show_time)
@pyqtSlot()
def start(self):
self.thread.start()
def stop(self):
if self.thread.isRunning():
self.thread.quit()
self.thread.wait()
print("Exit thread")
@pyqtSlot(object)
def show_time(self, timestamp):
print(
"Main thread {}: {}".format(
threading.get_ident(), timestamp.strftime("%d-%m-%Y %H-%M-%S")
)
)
def signal_handler(sig, frame):
print("Quit")
app.quit()
if __name__ == "__main__":
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
app = QCoreApplication(sys.argv)
timer = QTimer()
timer.timeout.connect(lambda: None)
timer.start(500)
print("Main thread {}".format(threading.get_ident()))
emitter = WorkerThread()
emitter.start()
sys.exit(app.exec_())
输出:
Main thread 140175719339648
Worker thread 140175659480832: Start timer
Worker thread 140175659480832: 26-07-2019 04-39-42
Main thread 140175719339648: 26-07-2019 04-39-42
Worker thread 140175659480832: 26-07-2019 04-39-43
Main thread 140175719339648: 26-07-2019 04-39-43
Worker thread 140175659480832: 26-07-2019 04-39-44
Main thread 140175719339648: 26-07-2019 04-39-44
Worker thread 140175659480832: 26-07-2019 04-39-45
Main thread 140175719339648: 26-07-2019 04-39-45
在 Qt/PyQt 中,我曾经使用 Worker class 和 QThread 创建线程。
self.worker = Worker()
self.thread = QThread()
worker.moveToThread(thread)
setup_signal_slot_with_main_object()
// start
thread.start()
我必须在 moveToThread() 之后放置 setup_signal_slot_with_main_object()。但是我有一个复杂的工人。在Worker.__ init__()中,它创建了许多QObjects并连接内部信号和槽。我不想创建一个在 worker->moveToThread(&thread) 之后建立所有连接和调用 worker.setup_signal_slot() 的方法因为 Worker 包含许多子 QObject,并且每个 QObject 都可以在其构造函数中创建 signal/slot。
在 Qt/C++ 中,我可以在 worker 的构造函数中建立 signal/slot 连接。但是在 PyQt 中,插槽不会 运行 在新线程中。
这是一个 Worker 包含 QTimer 的示例
import sys
import signal
import threading
from PyQt5.QtCore import QObject, pyqtSignal, QTimer, QCoreApplication, QThread
import datetime
class Worker(QObject):
timeChanged = pyqtSignal(object)
def __init__(self, parent=None):
QObject.__init__(self, parent)
self.timer = QTimer(self)
self.timer.setInterval(1000)
# I want to make connection at here
self.timer.timeout.connect(self.main_process)
def start(self):
# self.timer.timeout.connect(self.main_process)
self.timer.start()
print('Worker thread {}: Start timer'.format(threading.get_ident()))
# this method still run in main thread
def main_process(self):
timestamp = datetime.datetime.now()
print('Worker thread {}: {}'.format(threading.get_ident(), timestamp.strftime('%d-%m-%Y %H-%M-%S')))
self.timeChanged.emit(timestamp)
class WorkerThread(QObject):
def __init__(self, parent=None):
QObject.__init__(self, parent)
self.emitter = Worker()
self.thread = QThread(self)
self.emitter.moveToThread(self.thread)
self.thread.started.connect(self.emitter.start)
self.thread.finished.connect(self.emitter.deleteLater)
self.emitter.timeChanged.connect(self.show_time)
def start(self):
self.thread.start()
def stop(self):
if self.thread.isRunning():
self.thread.quit()
self.thread.wait()
print('Exit thread')
def show_time(self, timestamp):
print('Main thread {}: {}'.format(threading.get_ident(), timestamp.strftime('%d-%m-%Y %H-%M-%S')))
def signal_handler(sig, frame):
print('Quit')
app.quit()
if __name__ == '__main__':
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
app = QCoreApplication(sys.argv)
timer = QTimer()
timer.timeout.connect(lambda: None)
timer.start(500)
print('Main thread {}'.format(threading.get_ident()))
emitter = WorkerThread()
emitter.start()
sys.exit(app.exec_())
在Worker中,定时器超时会在主线程中调用main_process。我可以将 self.timer.timeout.connect(self.main_process) 移动到方法 worker.start() 中。但是正如我上面所说,我仍然想在它的构造函数中放置 internal signal/slot 。 谁能建议我一个解决方案?谢谢!
如果您希望在接收方使用 pyqtSlot()
装饰器的同一线程中调用这些方法,如果您不这样做,那么它将在发送方的线程中调用。
import sys
import signal
import threading
import datetime
from PyQt5.QtCore import QObject, pyqtSignal, QTimer, QCoreApplication, QThread, pyqtSlot
class Worker(QObject):
timeChanged = pyqtSignal(object)
def __init__(self, parent=None):
QObject.__init__(self, parent)
self.timer = QTimer(self)
self.timer.setInterval(1000)
self.timer.timeout.connect(self.main_process)
@pyqtSlot()
def start(self):
self.timer.start()
print("Worker thread {}: Start timer".format(threading.get_ident()))
@pyqtSlot()
def main_process(self):
timestamp = datetime.datetime.now()
print(
"Worker thread {}: {}".format(
threading.get_ident(), timestamp.strftime("%d-%m-%Y %H-%M-%S")
)
)
self.timeChanged.emit(timestamp)
class WorkerThread(QObject):
def __init__(self, parent=None):
QObject.__init__(self, parent)
self.emitter = Worker()
self.thread = QThread(self)
self.emitter.moveToThread(self.thread)
self.thread.started.connect(self.emitter.start)
self.thread.finished.connect(self.emitter.deleteLater)
self.emitter.timeChanged.connect(self.show_time)
@pyqtSlot()
def start(self):
self.thread.start()
def stop(self):
if self.thread.isRunning():
self.thread.quit()
self.thread.wait()
print("Exit thread")
@pyqtSlot(object)
def show_time(self, timestamp):
print(
"Main thread {}: {}".format(
threading.get_ident(), timestamp.strftime("%d-%m-%Y %H-%M-%S")
)
)
def signal_handler(sig, frame):
print("Quit")
app.quit()
if __name__ == "__main__":
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
app = QCoreApplication(sys.argv)
timer = QTimer()
timer.timeout.connect(lambda: None)
timer.start(500)
print("Main thread {}".format(threading.get_ident()))
emitter = WorkerThread()
emitter.start()
sys.exit(app.exec_())
输出:
Main thread 140175719339648
Worker thread 140175659480832: Start timer
Worker thread 140175659480832: 26-07-2019 04-39-42
Main thread 140175719339648: 26-07-2019 04-39-42
Worker thread 140175659480832: 26-07-2019 04-39-43
Main thread 140175719339648: 26-07-2019 04-39-43
Worker thread 140175659480832: 26-07-2019 04-39-44
Main thread 140175719339648: 26-07-2019 04-39-44
Worker thread 140175659480832: 26-07-2019 04-39-45
Main thread 140175719339648: 26-07-2019 04-39-45