假设我有一个 PyQt GUI 应用程序和一个使用
QTimer
在后台运行的 QThread
。 QTimer
设置为1秒间隔,无限运行。
现在主线程正忙于一些外部 C 库调用并阻塞 1 分钟。在此期间,
QTimer
会继续被触发并发出信号吗?
我正处于概念阶段,所以还没有代码可以显示。我知道在后台线程本身中进行大调用会更有意义。
简而言之,是的,QTimer 将在另一个线程上更新,前提是您自己负责线程的生命周期并仅在最合适的时间退出它。还要小心
QTimer's
引用,因此它不会被 python 的垃圾收集器收集(您需要在某一时刻停止 QTimer
)。
现在,用一些代码来说明一个更实际的示例,以便您可以自己测试一下:
from PySide2.QtWidgets import QApplication, QMainWindow
from PySide2.QtWidgets import QWidget, QVBoxLayout, QLabel, QPushButton
from PySide2.QtCore import QObject, QThread, QTimer, Signal
class TimerWorker(QObject):
timeout = Signal(int)
def __init__(self):
QObject.__init__(self)
self.count = 0
def run(self):
self.timer = QTimer()
self.timer.setInterval(250)
self.timer.timeout.connect(self.process)
self.timer.start()
def finished(self):
self.timer.stop()
def process(self):
self.count += 1
self.timeout.emit(self.count)
class Window(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
# Widgets
self.scene = QWidget()
self.label = QLabel("Count: 0")
self.busyBt = QPushButton("Sleep")
self.busyBt.clicked.connect(self.becomeBusy)
# Scene
layout = QVBoxLayout()
layout.addWidget(self.label)
layout.addWidget(self.busyBt)
self.scene.setLayout(layout)
self.setCentralWidget(self.scene)
# Threads
self.thread = QThread()
self.worker = TimerWorker()
self.worker.moveToThread(self.thread)
self.worker.timeout.connect(self.processCount)
self.thread.started.connect(self.worker.run)
self.thread.finished.connect(self.worker.finished)
self.thread.start()
def becomeBusy(self):
timeout = 5
print('Main Thread: Sleeping for %d seconds...' % (timeout))
QThread.sleep(timeout)
print('Main Thread: Awaken')
def processCount(self, count):
self.label.setText("Count: %d" % (count))
def closeEvent(self, evt):
self.thread.quit()
self.thread.wait()
if __name__ == '__main__':
app = QApplication()
win = Window()
win.show()
app.exec_()
在此示例中,我们启动一个
QThread
,它在其他线程上执行
TimerWorker.run()
(使用 moveToThread 方法)。每 0.25 秒,它会发出一个安排在主线程上的信号,以更新QLabel
文本。
同时,用户可以单击
QPushButton
来停止主线程5秒。在此期间,应用程序将冻结。
通过执行脚本并单击
QPushButton
冻结主线程,QTimer
继续运行并从 其他线程发出信号。但由于主线程正在休眠(或繁忙),因此信号永远不会被处理。该信号只会在主线程唤醒后才会被处理。
因此,如果您需要保持 GUI 始终响应客户端(并始终处理发出的信号),建议您在 QThread
侧完成所有
繁重工作,以免应用程序冻结一段时间.