Timers

QObject 是所有 Qt 对象的基类, 它提供基本的计时器支持. 使用 QObject::startTimer(), 你可以启动一个计时器(单位 ms). 这个函数返回一个唯一的整数计时器 ID. 这个定时器开始定时触发, 你可以调用 QObject::killTimer() 停止定时器, 参数是定时器 ID.

这个机制必须在事件循环中运行. 你可以使用 QApplication::exec() 启动事件循环. 当定时器触发时, 应用程序发发送 QTimerEvent, 控制流离开事件循环, 直到处理完定时器事件. 这就意味着, 当应用程序忙于执行其他操作时, 定时操作无法触发. 换句话说, 定时器的准确性取决于应用程序的粒度.

在多线程应用程序中, 你可以在任何具有事件循环的线程中使用定时器机制. 要在非 GUI 线程中启动事件循环, 使用 QThread::exec(). Qt 使用对象的 线程亲和性(thread affinity) 确定哪个线程将传递 QTimerEvent. 因此, 你必须在对象的线程中启动和停止定时器; 你无法在另一个线程中启动对象的定时器.

定时的间隔值的上限是一个有符号的整数, 单位是ms(实际上, 这是一个略大于 24 天的时间段). 精度取决于底层操作系统. Windows 2000 的精度是 15 毫米; 其他操作系统可以处理 1 毫米的间隔.

定时器功能的主要 API 是 QTimer. 这个类继承 QObject, 提供常规定时功能, 它非常适合大多数 GUI 程序的所有权结构. 通常情况下, 它的使用方式如下:


      QTimer *timer = new QTimer(this);
      connect(timer, SIGNAL(timeout()), this, SLOT(updateCaption()));
      timer->start(1000);

QTimer 对象是 widget 的子对象, 因此, 删除 widget 时, 也会同步删除定时器. 下一句, 定时器的 timeout() 信号连结到槽函数, 它以 1000 ms 的间隔启动, 也就是每秒超时一次.

QTimer 也提供一个静态函数, 实现单次定时器. 例如:


      QTimer::singleShot(200, this, SLOT(updateCaption()));

200 ms (0.2 s) 之后, updateCaption() 槽函数被调用.

QTimer 想要正常工作, 应用程序必须有一个事件循环; 因此, 你必须在某些地方调用 QCoreApplication::exec(). 只有事件循环运行时, 才会发送定时事件.

在多线程应用程序中, 你可以在任何有事件循环的线程中使用 QTimer. 要从非 GUI 线程中启动事件循环, 使用 QThread::exec(). Qt 使用定时器的 线程亲和性(thread affinity), 确定在哪个线程发出 timeout() 信号. 因此, 你必须在相关线程中启动和停止定时器; 不能从其他线程中启动定时器.

Analog Clock 示例展示如何使用 QTimer 重绘 widget. AnalogClock 的实现方式如下:


  AnalogClock::AnalogClock(QWidget *parent)
      : QWidget(parent)
  {
      QTimer *timer = new QTimer(this);
      connect(timer, SIGNAL(timeout()), this, SLOT(update()));
      timer->start(1000);
      ...
  }

每秒, QTimer 会使 QWidget::update() 槽函数被调用, 刷新时钟.

如果你已经有一个 QObject 的子类, 想有一个简单的优化, 你可以使用 QBasicTimer 替换 QTimer. 使用 QBasicTimer, 你必须重新实现 QObject::timerEvent(), 处理定时事件. Wiggly 示例展示如何使用 QBasicTimer.