QObject本身自带的定时器函数,简单的定时任务不需要再使用QTimer,只需要重写timerEvent即可。
interval单位是毫秒,且必须大于等于0
如果interval为0,则每当没有更多的窗口系统事件需要处理时,计时器事件发生一次。
Qt::TimerType:枚举类型有3个值
Qt::PreciseTimer :精确计时器试图保持毫秒级的精度
Qt::CoarseTimer :粗定时器试图将准确度保持在所需间隔的5%以内(默认值)
Qt::VeryCoarseTimer :非常粗糙的计时器只保持完整的秒精度
返回定时器标识符,如果无法启动定时器则返回零。
int QObject::startTimer(int interval, Qt::TimerType timerType)
{
Q_D(QObject);
if (Q_UNLIKELY(interval < 0)) {
qWarning("QObject::startTimer: Timers cannot have negative intervals");
return 0;
}
auto thisThreadData = d->threadData.loadRelaxed();
if (Q_UNLIKELY(!thisThreadData->hasEventDispatcher())) {
qWarning("QObject::startTimer: Timers can only be used with threads started with QThread");
return 0;
}
//必须在同一线程调用才有效
if (Q_UNLIKELY(thread() != QThread::currentThread())) {
qWarning("QObject::startTimer: Timers cannot be started from another thread");
return 0;
}
//向事件分发器注册定时器
int timerId = thisThreadData->eventDispatcher.loadRelaxed()->registerTimer(interval, timerType, this);
if (!d->extraData)
d->extraData = new QObjectPrivate::ExtraData;
d->extraData->runningTimers.append(timerId);//append意味着可以添加多个定时器
return timerId;
}
registerTimer-》timerInsert(将timer加入列表当中,并按照触发先后顺序排列)
void QTimerInfoList::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object)
{
QTimerInfo *t = new QTimerInfo;
t->id = timerId;
t->interval = interval;
t->timerType = timerType;
t->obj = object;
t->activateRef = nullptr;
timespec expected = updateCurrentTime() + interval;
t->timeout = expected;//超时时间
timerInsert(t);
}
每次事件循环processEvents时,调用activateTimers处理
int QTimerInfoList::activateTimers()
{
int n_act = 0, maxCount = 0;
firstTimerInfo = nullptr;
timespec currentTime = updateCurrentTime();
//先找到所有到期的定时器,后面依次调用sendEvent触发timerEvent处理事件
for (QTimerInfoList::const_iterator it = constBegin(); it != constEnd(); ++it) {
if (currentTime < (*it)->timeout)
break;
maxCount++;
}
while (maxCount--) {
if (isEmpty())
break;
QTimerInfo *currentTimerInfo = constFirst();
if (currentTime < currentTimerInfo->timeout)
break; // no timer has expired
removeFirst();
//从这里可以看出,下次触发时间是在调用timerevent前就已经计算好了的,
//如果timerevent执行时间较长大于时间间隔interval,下次事件循环判断其超时会直接触发
calculateNextTimeout(currentTimerInfo, currentTime);//计算下次触发时间
timerInsert(currentTimerInfo);//下次的超时信息并加入到超时列表里面,按照超时先后顺序排列的
if (!currentTimerInfo->activateRef) {
QTimerEvent e(currentTimerInfo->id);
QCoreApplication::sendEvent(currentTimerInfo->obj, &e);//最终调用到timerevent,同步触发
}
}
return n_act;
}
void QTimerInfoList::timerInsert(QTimerInfo *ti)
{
int index = size();
while (index--) {
const QTimerInfo * const t = at(index);
if (!(ti->timeout < t->timeout))//按触发先后顺序排列,timeout小的排在前面
break;
}
insert(index+1, ti);
}
id为startTimer的返回值
killTimer被调用时将结束对应的定时器,其不再触发timerEvent事件。
注意:不能在另一个线程里面结束它,即在另一个线程调用此函数无效,定时器不会被结束
void QObject::killTimer(int id)
{
Q_D(QObject);
//不能在另一个线程里面结束它
if (Q_UNLIKELY(thread() != QThread::currentThread())) {
qWarning("QObject::killTimer: Timers cannot be stopped from another thread");
return;
}
if (id) {
auto thisThreadData = d->threadData.loadRelaxed();
if (thisThreadData->hasEventDispatcher())
thisThreadData->eventDispatcher.loadRelaxed()->unregisterTimer(id);
d->extraData->runningTimers.remove(at);
QAbstractEventDispatcherPrivate::releaseTimerId(id);
}
}
bool QTimerInfoList::unregisterTimer(int timerId)
{
// set timer inactive
for (int i = 0; i < count(); ++i) {
QTimerInfo *t = at(i);
if (t->id == timerId) {
//移除
removeAt(i);
if (t == firstTimerInfo)
firstTimerInfo = nullptr;
if (t->activateRef)
*(t->activateRef) = nullptr;
delete t;
return true;
}
}
// id not found
return false;
}
QObject默认空实现
void QObject::timerEvent(QTimerEvent *)
{
}
一般都是继承后重写实现自己的功能
myobject.h
#include
class myobject : public QObject
{
Q_OBJECT
public:
myobject(QObject *parent = nullptr):QObject(parent){
}
protected:
virtual void timerEvent(QTimerEvent *event);
};
myobject.cpp
#include
virtual void timerEvent(QTimerEvent *event)
{
qDebug()<<"timerId="<timerId();
}
main.cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
myobject *obj1= new myobject(nullptr);
obj1->startTimer(1000);
obj1->startTimer(5000);
obj1->startTimer(10000);
return a.exec();
}