92-多线程、线程池、定时器- 定时器QTimer

在一般情况下,应用程序都是单线程运行的,但是对于 GUI程序来说,单线程有时满足不了需求。

例如,如果需要执行一个特别耗时的操作,在执行过程中整个程序就会卡顿,此时用户可能以为程序出错,所以就把程序关闭了;

或者 Widows 系统也认为程序出错,自动关闭程序。要解决这种问题就涉及多线程的知识。

一般来说,多线程技术涉及3种方法:

  • 一是使用计时器模块QTimer
  • 二是使用多线程模块QThread
  • 三是使用事件处理功能。

定时器QTimer

定时器

定时器 QTimer 像个闹钟,其作用是经过一个固定的时间间隔发送一个信号,执行与信号连接的槽函数,实现自动完成某些功能。

可以设置定时器只发送一次信号,或多次发送信号;

可以启动发送信号,也可以停止发送信号。

用QTimer 创建定时器的方法如下所示,其中parent 是继承自QObejct 的对象。QTimer 是不可见的,当父类删除时,定时器也同时删除。

from PySide6.QtCore import QTimer

QTimer(parent: Union[PySide6.QtCore.QObject,NoneType]= None)-> None

如果要在应用程序中周期性地执行某个操作,如周期性地检测主机的 CPU值,则需要使用QTimer(定时器),QTimer 类提供了重复的和单次的定时器。

要使用定时器,需要先创建一个QTimer实例,将其 timeout 信号连接到相应的槽,并调用start()函数。

然后定时器会以恒定的间隔发射 timeout 信号。start(2000)表示设置时间间隔为2秒并启动定时器,代码如下:

from PySide6.QtCore import QTimer

# 初始化一个定时器
self.timer = QTimer(self)
# 计时结束并调用 operate()
# 设置时间间隔并启动定时器
self.timer.timeout.connect(self.operate)
self.timer.start(2000)

在默认情况下,isSingleShot0返回 False,如果返回 True,则计时器信号只会触发一次,可以通过 setSingleShot(True)修改默认值

计时器的另一种使用方法是延迟计时,这种方法要使用 sigleShot 信号(前者是timeout 信号),如 singleShot(5000,receiver)表示5 秒之后会触发 receiver 信号。

定时器QTimer的说明

QTimer类为定时器提供了一个高级编程接口。要使用它,请创建一个QTimer,将其timeout()信号连接到适当的插槽,然后调用start()。从那时起,它将以恒定的间隔发出timeout()信号。
1秒(1000毫秒)计时器的示例(来自模拟时钟示例):

timer = QTimer(self)
timer.timeout.connect(this,QOverload<>::of(&AnalogClock::update))
timer.start(1000)

从那时起,update()槽将每秒调用一次。
您可以通过调用setSingleShot(true)将计时器设置为仅超时一次。您也可以使用静态singleShot()函数在指定的时间间隔后调用插槽:

QTimer::singleShot(200,self.updateCaption)

在多线程应用程序中,可以在任何具有事件循环的线程中使用QTimer。要从非GUI线程启动事件循环,请使用exec()。Qt使用计时器的线程相关性来确定哪个线程将发出timeout()信号。因此,您必须在其线程中启动和停止计时器;不可能从另一个线程启动计时器。
作为一种特殊情况,超时为0的QTimer将尽快超时,尽管零计时器和其他事件源之间的顺序未指定。零定时器可以用来做一些工作,同时仍然提供快速的用户界面:

timer = QTimer(self)

从那时起,processOneThing()将被反复调用。它应该以这样一种方式编写,即它总是快速返回(通常在处理一个数据项之后),以便Qt可以将事件传递到用户界面,并在完成所有工作后立即停止计时器。这是在GUI应用程序中实现繁重工作的传统方式,但随着多线程现在在越来越多的平台上变得可用,我们预计零毫秒的QTimer对象将逐渐被QThread s所取代。

精度和计时器分辨率

计时器的准确性取决于底层操作系统和硬件。大多数平台支持1毫秒的分辨率,尽管在许多现实世界的情况下,计时器的精度不会等于这个分辨率。
精确度也取决于计时器类型。对于PreciseTimer,QTimer将尝试将精度保持在1毫秒。精确的计时器也永远不会比预期的更早超时。
对于CoarseTimer和VeryCoarseTimer类型,QTimer可能比预期更早醒来,在这些类型的裕度范围内:CoarseTimer5%的间隔,VeryCoarceTimer 500ms的间隔。
如果系统繁忙或无法提供所要求的精度,则所有定时器类型的超时时间可能晚于预期。在这种超时超时的情况下,即使多个超时已经过期,Qt也只会发出一次timeout(),然后将恢复原始间隔。

QTimer的替代品

使用QTimer的另一种方法是为对象调用startTimer(),并在类(必须继承QObject)中重新实现timerEvent()事件处理程序。缺点是timerEvent()不支持诸如单次定时器或信号之类的高级功能。
另一种选择是QBasicTimer。它通常没有直接使用startTimer()那么麻烦。请参阅Timers以了解所有三种方法的概述。
一些操作系统限制了可以使用的定时器的数量;Qt试图绕过这些限制。

定时器QTimer的属性

属性描述访问功能
active: bool如果计时器正在运行,则此布尔属性为true;否则为false。isActive()
interval: int此属性保存超时间隔(以毫秒为单位)。
此属性的默认值为0。一旦处理完窗口系统的事件队列中的所有事件,超时间隔为0的QTimer就会超时。
设置活动计时器的间隔会更改其timerId()。
interval()

setInterval(msec)
remainingTime: int此属性保存剩余时间(以毫秒为单位)。
返回计时器的剩余值(以毫秒为单位),直到超时为止。如果计时器处于非活动状态,则返回的值将为-1。如果计时器过期,则返回的值将为0。
remainingTime()
singleShot: bool此属性保存计时器是否为单次计时器。
单触发计时器只触发一次,非单触发计时器每隔几毫秒触发一次。
此属性的默认值为false。
isSingleShot()

setSingleShot(singleShot)
timerType: TimerType此属性用于控制计时器的准确性。
此属性的默认值为Qt::CoarseTimer。
timerType()

setTimerType(atype)

定时器QTimer的常用方法

定时器QTimer的常用方法如表所示,主要方法介绍如下

QTimer的方法及参数类型返回值的类型说明
setInterval(msec:int)None设置信号发送的时间间隔(毫秒)
interval()int获取信号发送的时间间隔(毫秒)
isActive()bool获取定时器是否激活
如果计时器正在运行(挂起),则返回true;否则返回false。
属性的Getter处于活动状态。
setSingleShot(singleShot)设置取计时器是否为单次计时器。
isSingleShot()bool获取计时器是否为单次计时器。
单触发计时器只触发一次,非单触发计时器每隔几毫秒触发一次。
此属性的默认值为false。
remainingTime()int获取距下次发送信号的时间(毫秒)
setSingleShot(bool)None设置定时器是否为单次发送
isSingleShot()bool获取定时器是否为单次发送
setTimerType(atype: Qt.TimerType)None设置定时器的精度类型
timerType()Qt.TimerType获取定时器的精度类型
[slot]start(msec:int)None经过msec毫秒后启动定时器
[slot]start([msec])None此函数重载start()。
在间隔中指定的超时时间内启动或重新启动计时器。
如果计时器已经在运行,它将停止并重新启动。
如果singleShot为true,则计时器将只激活一次。
[slot]stop()None停止定时器
timerId()int获取定时器的ID号
[static]singleShot(int,Callable)None经过int毫秒后,调用Python的可执行函数 Callable
[static]singleShot(msec: int,receiver: QObject,member: str)None这个静态函数在给定的时间间隔后调用一个槽。
使用此函数非常方便,因为您不需要麻烦处理timerEvent或创建本地QTimer对象。
from PySide6.QtWidgets import QApplication
from PySide6.QtCore import QTimer
if name ==“main”:

app = QApplication([])
QTimer.singleShot(600000,app,QCoreApplication.quit)

sys.exit(app.exec())
此示例程序在10分钟(600000毫秒)后自动终止。
接收器是接收对象,成员是插槽。时间间隔为毫秒。
[static]singleShot(msec: int,timerType: Qt.TimerType,receiver:QObject,member: str)None这是一个重载函数。
这个静态函数在给定的时间间隔后调用一个槽。
使用此函数非常方便,因为您不需要麻烦处理timerEvent或创建本地QTimer对象。
接收器是接收对象,成员是插槽。时间间隔为毫秒。计时器类型会影响计时器的准确性。
  • 定时器的使用

    • 一般是先建立定时器对象,用setInterval(int)方法设置定时器发送信号的时间间隔,然后将定时器的信号 timeout 与某个槽函数关联最后用start()方法启动定时器。
    • 如果只需要定时器发送1次信号,可以设置 setSingleShot(bool)为True,否则将会连续不断地发送信号,可以用stop()方法停止定时器信号的发送
    • 如果只是 1次发送信号,也可以不用创建定时器对象,用定时器类的静态方法singleShot()直接连接某个控件的槽函数。
    • 如果定义了多个定时器,可以用timeld()方法获取定时器的编号。
  • 定时器的精度

    • 与系统和硬件有关用setTimerType(QtTimerType)方法可以设置定时器的精度,其中参数PySide6.QtCore.Qt.TimerType的取值如表所示:

      ConstantDescription
      Qt.PreciseTimer精密计时器试图保持毫秒的精度
      Qt.CoarseTimer粗略计时器试图将精度保持在所需间隔的5%以内
      Qt.VeryCoarseTimer非常粗糙的计时器只能保持完全的秒精度

定时器QTimer的信号

定时器只有一个信号 timeout(),每经过固定的时间间隔发送一次信号,或者只发送1次信号

也可以自定义信号,给定时间间隔后,在调用一个槽函数时发射信号

定时器QTimer 的应用实例

下面的程序定义了两个定时器,第1个定时器用于窗口背景图片的切换,第2个定时器用于设置按钮激活的时间,并改变按钮显示的文字,这里设置单击按钮后 10 秒激活按钮

image-20230226231742643image-20230226231641526

# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 22:00
# File_name: 定时器QTimer 的应用实例.py
from PySide6.QtWidgets import QApplication,QWidget,QPushButton
from PySide6.QtGui import QPainter,QPixmap,QBitmap
from PySide6.QtCore import QRect,QTimer
import sys


class MyWindow(QWidget):
    def __init__(self,parent=None):
        super().__init__(parent)
        self.setWindowTitle("定时器")
        path = r"../../Resources/animal//m1.png"
        self.pix = QPixmap(path)
        self.bit = QBitmap(path)
        self.rect = QRect(0,0,self.pix.width(),self.pix.height())
        self.resize(self.rect.size())

        self.timer_1 = QTimer(self)# 第1个定时器
        self.timer_1.setInterval(2000)# 第1个定时器的时间间隔连接
        self.timer_1.timeout.connect(self.timer_1_slot)# 第1个定时器信号与槽函数的

        self.timer_1.start()# 启动第1个定时器
        self.status = True  # 指示变量
        self.timer_2 = QTimer(self)# 第2个定时器
        self.timer_2.setInterval(1000)# 第2个定时器的时间间隔
        self.timer_2.timeout.connect(self.pushButton_enable)# 第2个定时器信号与槽函数的连接

        self.duration = 9  # 按钮激活时间
        self.pushButton = QPushButton("单击发送验证码",self)
        self.pushButton.setGeometry(10,10,200,30)
        self.pushButton.clicked.connect(self.timer_2.start)# 按钮单击信号与槽函数的#连接

    def timer_1_slot(self):
        self.status = not self.status
        self.update()# 更新窗口会发paintEvent(),调用paintEvent()函数

    def paintEvent(self,event):  # paintEvent 事件
        painter = QPainter(self)

        if self.status:
            painter.drawPixmap(self.rect,self.pix)
        else:
            painter.drawPixmap(self.rect,self.bit)

    def timer_2_start(self):  # 按钮的槽函数
        self.timer_2.start()
        self.pushButton.setEnabled(False)
        self.pushButton.setText(str(self.duration + 1)+"后可重新发送验证码")

    def pushButton_enable(self):
        if self.duration > 0:
            self.pushButton.setText(str(self.duration)+"后可重新发送验证码")
            self.duration = self.duration - 1
        else:
            self.pushButton.setEnabled(True)
            self.pushButton.setText("单击发送验证码")
            self.timer_2.stop()# 停止定时器
            self.duration = 9


if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = MyWindow()

    win.show()
    sys.exit(app.exec())

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

士别三日,当挖目相待

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值