本文共 3511 字,大约阅读时间需要 11 分钟。
在 PyQt5 中,由于 GUI 组件的创建和修改通常必须在主线程(QApplication 的实例所在线程)中进行,因此你不能从其他非主线程中启动定时器或者更改标签的大小等操作。以下是一些解决这一问题的方法。
pyqtSignal 和 moveToThread首先,你需要定义一个信号,然后在主线程中连接这个信号到一个槽函数,然后从槽函数中启动定时器或修改标签大小。
import sysfrom PyQt5.QtWidgets import QApplication, QLabel, QPushButtonfrom PyQt5.QtCore import QObject, Qt, pyqtSignal, QThread, Timer
class Worker(QObject): updateText = pyqtSignal(str) def __init__(self): super().__init__() self.timer = Timer() self.timer.timeout.connect(self.on_timer_timeout) self.timer.start(1000) # 每秒触发一次 @pyqtSlot() def onTimerTimeout(self): newText = "New Text" self.updateText.emit(newText)
class MainWindow(QWidget): def __init__(self): super().__init__() self.label = QLabel("Initial Text") layout = QVBoxLayout() layout.addWidget(self.label) button = QPushButton("Start") button.clicked.connect(self.start_worker) layout.addWidget(button) self.setLayout(layout) def start_worker(self): if not hasattr(self, 'worker'): self.worker = Worker() self.worker.updateText.connect(self.on_text_updated) app = QApplication([])window = MainWindow()window.show()if __name__ == '__main__': sys.exit(app.exec_())
QThreadPool 和 moveToThread另一种方法是将任务放入一个线程池中执行。
import sysfrom PyQt5.QtWidgets import QApplication, QLabel, QPushButtonfrom PyQt5.QtCore import Qt, pyqtSignal, QObject, QRunnable, QThreadPool
class Worker(QObject): updateText = pyqtSignal(str) def __init__(self): super().__init__() self.timer = Timer() self.timer.timeout.connect(self.on_timer_timeout) self.timer.start(1000) # 每秒触发一次 @pyqtSlot() def onTimerTimeout(self): newText = "New Text" self.updateText.emit(newText)
class WorkerRunnable(QRunnable): def __init__(self, worker): super().__init__() self.worker = worker def run(self): self.worker.start()
if __name__ == '__main__': app = QApplication([]) window = MainWindow() window.show() thread_pool = QThreadPool() worker = Worker() runnable = WorkerRunnable(worker) thread_pool.start(runnable) worker.updateText.connect(lambda text: window.label.setText(text)) sys.exit(app.exec_())
QMetaObject.invokeMethod如果你不能使用信号槽机制(如上两种方法),可以尝试通过 QMetaObject.invokeMethod 来间接在主线程中执行操作。
import sysfrom PyQt5.QtWidgets import QApplication, QLabelfrom PyQt5.QtCore import Qt, pyqtSlot, QThreadPool, QRunnable, QMetaObject
class Worker(QObject): def __init__(self, label): super().__init__() self.label = label self.timer = Timer() self.timer.timeout.connect(self.on_timer_timeout) self.timer.start(1000)
@pyqtSlot() def onTimerTimeout(self): newText = "New Text" QMetaObject.invokeMethod(self.label, "setText", Qt.DirectConnection, pyqtArgs(newText))
class MainWindow(QWidget): def __init__(self): super().__init__() self.label = QLabel("Initial Text") layout = QVBoxLayout() layout.addWidget(self.label) button = QPushButton("Start") button.clicked.connect(self.start_worker) layout.addWidget(button) self.setLayout(layout) def start_worker(self): if not hasattr(self, 'worker'): self.worker = Worker(self.label) if __name__ == '__main__': app = QApplication([]) window = MainWindow() window.show() sys.exit(app.exec_())
转载地址:http://hdafk.baihongyu.com/