gpt4 book ai didi

python - Qthread 上的 QTimer

转载 作者:行者123 更新时间:2023-12-04 14:22:49 24 4
gpt4 key购买 nike

我有一个 GUI 女巫,我需要使用 Qtimer 不断更新,为此我使用了一个工作 Qthread,这是我的代码:

from PyQt5.QtWidgets import QApplication, QPushButton, QWidget
from PyQt5.QtCore import QThread, QTimer
import sys
import threading


class WorkerThread(QThread):
def run(self):
print("thread started from :" + str(threading.get_ident()))
timer = QTimer(self)
timer.timeout.connect(self.work)
timer.start(5000)
self.exec_()

def work(self):
print("working from :" + str(threading.get_ident()))
QThread.sleep(5)


class MyGui(QWidget):

worker = WorkerThread()

def __init__(self):
super().__init__()
self.initUi()
print("Starting worker from :" + str(threading.get_ident()))
self.worker.start()

def initUi(self):
self.setGeometry(500, 500, 300, 300)
self.pb = QPushButton("Button", self)
self.pb.move(50, 50)
self.show()


app = QApplication(sys.argv)
gui = MyGui()
app.exec_()

输出是:
Starting worker from :824
thread started from :5916
working from :824
working from :824

计时器正在主线程上工作,女巫卡住了我的 Gui,我该如何解决?

最佳答案

答案:在你的情况下,我认为没有必要使用 QThread .
TL;博士;
我什么时候需要在 GUI 上下文中使用另一个线程?
当某个任务可以阻塞主线程称为GUI线程时,应该只使用一个线程,阻塞是因为任务耗时,导致GUI eventloop无法正常工作。所有现代 GUI 都在一个事件循环中执行,它允许您从键盘、鼠标等操作系统接收通知,还允许您根据用户修改 GUI 的状态。
在你的情况下,我没有看到任何繁重的任务,所以我认为不需要 QThread,我真的不知道你想要定期运行的任务是什么。
假设你有一个消耗大量时间的任务,比如说 30 秒,你必须每半小时做一次,那么线程是必要的。在您的情况下,您想使用 QTimer。
让我们分批进行,QTimer是一个继承自 QObject 的类, 和 QObject属于与父级相同的,如果它没有父级,则属于创建它的线程。另一方面,很多时候人们认为 QThread是Qt的一个线程,但不是,QThread是一个允许处理本地线程生命周期的类,这在 docs 中有明确说明。 :QThread 类提供了一种与平台无关的方式来 管理线程 .
了解了以上内容,我们来分析一下你的代码:

timer = QTimer(self)
在上面的代码中,self 是 QTimer 的父级,self 是 QThread , 所以 QTimer属于 QThread 的父线程或创建 QThread 的地方,而不是创建 QThread 的线程处理。
那我们看看代码在哪里 QThread被创建:
worker = WorkerThread()
正如我们看到的 QThread没有父级,则 QThread属于创建它的线程,即 QThread属于主线程,因此它的 QTimer child 也属于主线程。还要注意的是 QThread 的新线程句柄仅具有 run() 的范围method ,如果该方法在别处属于 QThread 所在的字段已创建,以上所有我们看到代码的输出是正确的,并且 QThread.sleep(5)在主线程上运行导致事件循环崩溃和 GUI 卡住。
所以解决方案是删除 QTimer 的父级以便它所属的线程是 run() 之一方法,并在同一方法内移动功函数。另一方面,不必要地创建静态属性是一种不好的做法,考虑到上述结果代码如下:
import sys
import threading
from PyQt5.QtCore import QThread, QTimer
from PyQt5.QtWidgets import QApplication, QPushButton, QWidget


class WorkerThread(QThread):
def run(self):
def work():
print("working from :" + str(threading.get_ident()))
QThread.sleep(5)
print("thread started from :" + str(threading.get_ident()))
timer = QTimer()
timer.timeout.connect(work)
timer.start(10000)
self.exec_()

class MyGui(QWidget):
def __init__(self):
super().__init__()
self.initUi()
self.worker = WorkerThread(self)
print("Starting worker from :" + str(threading.get_ident()))
self.worker.start()

def initUi(self):
self.setGeometry(500, 500, 300, 300)
self.pb = QPushButton("Button", self)
self.pb.move(50, 50)


if __name__ == '__main__':
app = QApplication(sys.argv)
gui = MyGui()
gui.show()
sys.exit(app.exec_())
输出:
Starting worker from :140068367037952
thread started from :140067808999168
working from :140067808999168
working from :140067808999168
观察:
  • 已模拟的繁重任务为 5 秒,该任务必须每 10 秒执行一次。如果您的任务花费的时间比您应该创建其他线程的时间长。
  • 如果您的任务是执行一项不像显示时间那么繁重的周期性任务,那么不要使用新线程,因为您正在为简单任务增加复杂性,此外这可能会导致调试和测试阶段更加复杂。
  • 关于python - Qthread 上的 QTimer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52036021/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com