计时器

QObject 是所有 Qt 对象的基类,在 Qt 中提供基本计时器支持。采用 QObject::startTimer (),采用间隔 (以毫秒为单位) 作为自变量启动计时器。函数返回唯一整型计时器 ID。然后以常规间隔激发计时器,直到明确调用 QObject::killTimer () 采用该计时器 ID。

代替直接处理计时器 ID,可以使用 QBasicTimer . QBasicTimer 是值类, RAII 包裹器围绕计时器 ID。启动计时器采用 QBasicTimer::start (),和停止它采用 QBasicTimer::stop () (后者还会被调用当销毁时)。要使用 QBasicTimer ,必须重实现 timerEvent () 在类 (必须是子类化的 QObject ),并在那里处理计时器事件。

此机制要工作,应用程序必须在事件循环中运行。可以启动事件循环采用 QApplication::exec ()。当计时器激发时,应用程序发送 QTimerEvent ,并控制流离开事件循环,直到计时器事件被处理。这隐含计时器无法被激发,当应用程序忙于做某些事情时。换句话说:计时器精度从属应用程序的粒度。

在多线程应用程序中,可以在拥有事件循环的任何线程中使用计时器机制。要从非 GUI 线程启动事件循环,使用 QThread::exec ()。Qt 使用对象的 线程亲缘关系 确定哪个线程将交付 QTimerEvent 。因此,必须启动和停止对象线程中的所有计时器;为另一线程中的对象启动计时器,是不可能的。

计时器功能的主要 API 是 QTimer . QTimer 以有符号整数存储间隔,把它支持的最大间隔,以有符号整数限制到可以拟合的毫秒数 (实际上,这大约是 24 天的周期)。

Qt 6.8 引入了 QChronoTimer 类。2 个类的主要差异是 QChronoTimer 支持更大间隔范围和更高精度 ( std::chrono::nanoseconds )。对于 QTimer 最大支持间隔为 ±24 天,而 QChronoTimer 是 ±292 年。若只需要毫秒分辨率和 ±24 天范围,可以继续使用 QTimer 。注意, QChronoTimer 的存在主要是因为 QTimer 的精度无法被改为 std::chrono::nanoseconds 不破坏二进制兼容性。

计时器的精度从属底层 OS (操作系统)。Windows 2000 拥有 15ms 精度;我们有测试过其它系统,可以处理 1ms 间隔。

QTimer 提供发射信号的常规计时器,当计时器激发时,并继承自 QObject 因此,它能很好适应大多数 Qt 程序的所有权结构。正常使用它的方式像这样:

        QTimer *timer = new QTimer(1s, this);
        connect(timer, &QTimer::timeout, this, &MyWidget::processOneThing);
        timer->start();
        auto *timer = new QTimer(this);
        connect(timer, &QTimer::timeout, this, &MyWidget::processOneThing);
        timer->setInterval(1s);
        timer->start();
					

The QTimer 对象被制作成子级对于 this 对象,因此当 this 被销毁,计时器也被销毁。接下来, timeout () 信号被连接到将做工作的槽,可以把计时器间隔传递给构造函数,或稍后设置采用 setInterval()。

QTimer 还为单发计时器提供静态函数。例如:

        MyWidget widget;
        QTimer::singleShot(200ms, &widget, &MyWidget::updateCaption);
					

200 毫秒后这执行代码行, updateCaption() 槽将被调用。

For QTimer 要工作,应用程序必须拥有事件循环;也就是说,必须调用 QCoreApplication::exec () 在某些地方。才交付计时器事件,当事件循环在运行时。

在多线程应用程序中,可以使用 QTimer 在拥有事件循环的任何线程中。要从非 GUI 线程启动事件循环,使用 QThread::exec ()。Qt 使用计时器的 线程亲缘关系 确定哪个线程将发射 timeout () 信号。因此这,必须在其线程中启动和停止计时器;从另一线程启动计时器,是不可能的。

The 指针式时钟 范例展示如何使用 QTimer 以按定期间隔重新绘制 Widget。来自 AnalogClock 的实现:

AnalogClock::AnalogClock(QWidget *parent)
    : QWidget(parent)
{
    QTimer *timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, QOverload<>::of(&AnalogClock::update));
    timer->start(1000);
    setWindowTitle(tr("Analog Clock"));
    resize(200, 200);
}
					

每秒, QTimer 会调用 QWidget::update () 槽以刷新时钟的显示。