Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qtimer.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qtimer.h"
6#include "qtimer_p.h"
8
12#include "qdeadlinetimer.h"
13#include "qmetaobject_p.h"
14#include "qobject_p.h"
15#include "qproperty_p.h"
16#include "qthread.h"
17
18using namespace std::chrono_literals;
19
21
23 = default;
24
25/*!
26 \class QTimer
27 \inmodule QtCore
28 \brief The QTimer class provides repetitive and single-shot timers.
29
30 \ingroup events
31
32
33 The QTimer class provides a high-level programming interface for
34 timers. To use it, create a QTimer, connect its timeout() signal
35 to the appropriate slots, and call start(). From then on, it will
36 emit the timeout() signal at constant intervals.
37
38 Example for a one second (1000 millisecond) timer (from the
39 \l{widgets/analogclock}{Analog Clock} example):
40
41 \snippet ../widgets/widgets/analogclock/analogclock.cpp 4
42 \snippet ../widgets/widgets/analogclock/analogclock.cpp 5
43 \snippet ../widgets/widgets/analogclock/analogclock.cpp 6
44
45 From then on, the \c update() slot is called every second.
46
47 You can set a timer to time out only once by calling
48 setSingleShot(true). You can also use the static
49 QTimer::singleShot() function to call a slot after a specified
50 interval:
51
52 \snippet timers/timers.cpp 3
53
54 In multithreaded applications, you can use QTimer in any thread
55 that has an event loop. To start an event loop from a non-GUI
56 thread, use QThread::exec(). Qt uses the timer's
57 \l{QObject::thread()}{thread affinity} to determine which thread
58 will emit the \l{QTimer::}{timeout()} signal. Because of this, you
59 must start and stop the timer in its thread; it is not possible to
60 start a timer from another thread.
61
62 As a special case, a QTimer with a timeout of 0 will time out as soon as
63 possible, though the ordering between zero timers and other sources of
64 events is unspecified. Zero timers can be used to do some work while still
65 providing a snappy user interface:
66
67 \snippet timers/timers.cpp 4
68 \snippet timers/timers.cpp 5
69 \snippet timers/timers.cpp 6
70
71 From then on, \c processOneThing() will be called repeatedly. It
72 should be written in such a way that it always returns quickly
73 (typically after processing one data item) so that Qt can deliver
74 events to the user interface and stop the timer as soon as it has done all
75 its work. This is the traditional way of implementing heavy work
76 in GUI applications, but as multithreading is nowadays becoming available on
77 more and more platforms, we expect that zero-millisecond
78 QTimer objects will gradually be replaced by \l{QThread}s.
79
80 \section1 Accuracy and Timer Resolution
81
82 The accuracy of timers depends on the underlying operating system
83 and hardware. Most platforms support a resolution of 1 millisecond,
84 though the accuracy of the timer will not equal this resolution
85 in many real-world situations.
86
87 The accuracy also depends on the \l{Qt::TimerType}{timer type}. For
88 Qt::PreciseTimer, QTimer will try to keep the accuracy at 1 millisecond.
89 Precise timers will also never time out earlier than expected.
90
91 For Qt::CoarseTimer and Qt::VeryCoarseTimer types, QTimer may wake up
92 earlier than expected, within the margins for those types: 5% of the
93 interval for Qt::CoarseTimer and 500 ms for Qt::VeryCoarseTimer.
94
95 All timer types may time out later than expected if the system is busy or
96 unable to provide the requested accuracy. In such a case of timeout
97 overrun, Qt will emit timeout() only once, even if multiple timeouts have
98 expired, and then will resume the original interval.
99
100 \section1 Alternatives to QTimer
101
102 Qt 6.8 introduced QChronoTimer. The main difference between the two
103 classes, is that QChronoTimer supports a larger interval range and a
104 higher precision (\c std::chrono::nanoseconds). For QTimer the maximum
105 supported interval is ±24 days, whereas for QChronoTimer it is ±292
106 years (less chances of interger overflow with intervals longer than
107 \c std::numeric_limits<int>::max()). If you only need millisecond
108 resolution and ±24 days range, you can continue to use QTimer.
109
110 \include timers-common.qdocinc q-chrono-timer-alternatives
111
112 Some operating systems limit the number of timers that may be
113 used; Qt tries to work around these limitations.
114
115 \sa QBasicTimer, QTimerEvent, QObject::timerEvent(), Timers,
116 {Analog Clock}
117*/
118
119/*!
120 Constructs a timer with the given \a parent.
121*/
122
123QTimer::QTimer(QObject *parent)
124 : QObject(*new QTimerPrivate(this), parent)
125{
126 Q_ASSERT(d_func()->isQTimer);
127}
128
129
130/*!
131 Destroys the timer.
132*/
133
134QTimer::~QTimer()
135{
136 if (d_func()->isActive()) // stop running timer
137 stop();
138}
139
140
141/*!
142 \fn void QTimer::timeout()
143
144 This signal is emitted when the timer times out.
145
146 \sa interval, start(), stop()
147*/
148
149/*!
150 \property QTimer::active
151 \since 4.3
152
153 This boolean property is \c true if the timer is running; otherwise
154 false.
155*/
156
157/*!
158 \fn bool QTimer::isActive() const
159
160 Returns \c true if the timer is running; otherwise returns \c false.
161*/
162bool QTimer::isActive() const
163{
164 return d_func()->isActiveData.value();
165}
166
167QBindable<bool> QTimer::bindableActive()
168{
169 return QBindable<bool>(&d_func()->isActiveData);
170}
171
172/*!
173 \fn int QTimer::timerId() const
174
175 Returns the ID of the timer if the timer is running; otherwise returns
176 -1.
177*/
178int QTimer::timerId() const
179{
180 auto v = qToUnderlying(id());
181 return v == 0 ? -1 : v;
182}
183
184/*!
185 \since 6.8
186 Returns a Qt::TimerId representing the timer ID if the timer is running;
187 otherwise returns \c Qt::TimerId::Invalid.
188
189 \sa Qt::TimerId
190*/
191Qt::TimerId QTimer::id() const
192{
193 return d_func()->id;
194}
195
196/*! \overload start()
197
198 Starts or restarts the timer with the timeout specified in \l interval.
199
200//! [stop-restart-timer]
201 If the timer is already running, it will be
202 \l{QTimer::stop()}{stopped} and restarted. This will also change its id().
203//! [stop-restart-timer]
204
205//! [singleshot-activation]
206 If \l singleShot is true, the timer will be activated only once.
207//! [singleshot-activation]
208
209//! [eventloop-busy]
210 \note Keeping the event loop busy with a zero-timer is bound to
211 cause trouble and highly erratic behavior of the UI.
212//! [eventloop-busy]
213*/
214void QTimer::start()
215{
216 Q_D(QTimer);
217 if (d->isActive()) // stop running timer
218 stop();
219
220 Qt::TimerId newId{ QObject::startTimer(d->inter * 1ms, d->type) }; // overflow impossible
221 if (newId > Qt::TimerId::Invalid) {
222 d->id = newId;
223 d->isActiveData.notify();
224 }
225}
226
227/*!
228 Starts or restarts the timer with a timeout interval of \a msec
229 milliseconds.
230
231 This is equivalent to:
232
233 \code
234 timer.setInterval(msec);
235 timer.start();
236 \endcode
237
238 \include qtimer.cpp stop-restart-timer
239
240 \include qtimer.cpp singleshot-activation
241
242 \include timers-common.qdocinc negative-intervals-not-allowed
243
244 \include qtimer.cpp eventloop-busy
245*/
246void QTimer::start(int msec)
247{
248 start(msec * 1ms);
249}
250
251static std::chrono::milliseconds
252checkInterval(const char *caller, std::chrono::milliseconds interval)
253{
254 constexpr auto maxInterval = INT_MAX * 1ms;
255 if (interval < 0ms) {
256 qWarning("%s: negative intervals aren't allowed; the interval will be set to 1ms.", caller);
257 interval = 1ms;
258 } else if (interval > maxInterval) {
259 qWarning("%s: interval exceeds maximum allowed interval, it will be clamped to "
260 "INT_MAX ms (about 24 days).", caller);
261 interval = maxInterval;
262 }
263 return interval;
264}
265
266/*!
267 \since 5.8
268 \overload
269
270 Starts or restarts the timer with a timeout of duration \a interval milliseconds.
271
272 This is equivalent to:
273
274 \code
275 timer.setInterval(interval);
276 timer.start();
277 \endcode
278
279 \include qtimer.cpp stop-restart-timer
280
281 \include qtimer.cpp singleshot-activation
282
283 \include timers-common.qdocinc negative-intervals-not-allowed
284
285 \include qtimer.cpp eventloop-busy
286*/
287void QTimer::start(std::chrono::milliseconds interval)
288{
289 Q_D(QTimer);
290
291 interval = checkInterval("QTimer::start", interval);
292 const int msec = interval.count();
293 const bool intervalChanged = msec != d->inter;
294 d->inter.setValue(msec);
295 start();
296 if (intervalChanged)
297 d->inter.notify();
298}
299
300
301
302/*!
303 Stops the timer.
304
305 \sa start()
306*/
307
308void QTimer::stop()
309{
310 Q_D(QTimer);
311 if (d->isActive()) {
312 QObject::killTimer(d->id);
313 d->id = Qt::TimerId::Invalid;
314 d->isActiveData.notify();
315 }
316}
317
318
319/*!
320 \reimp
321*/
322void QTimer::timerEvent(QTimerEvent *e)
323{
324 Q_D(QTimer);
325 if (e->id() == d->id) {
326 if (d->single)
327 stop();
328 emit timeout(QPrivateSignal());
329 }
330}
331
332QAbstractEventDispatcher::Duration // statically asserts that Duration is nanoseconds
333QTimer::from_msecs(std::chrono::milliseconds ms)
334{
335 using Duration = QAbstractEventDispatcher::Duration;
336
337 using namespace std::chrono;
338 using ratio = std::ratio_divide<std::milli, Duration::period>;
339 static_assert(ratio::den == 1);
340
341 Duration::rep r;
342 if (qMulOverflow<ratio::num>(ms.count(), &r)) {
343 qWarning("QTimer::singleShot(std::chrono::milliseconds, ...): "
344 "interval argument overflowed when converted to nanoseconds.");
345 return Duration::max();
346 }
347 return Duration{r};
348}
349
350/*!
351 \internal
352
353 Implementation of the template version of singleShot
354
355 \a msec is the timer interval
356 \a timerType is the timer type
357 \a receiver is the receiver object, can be null. In such a case, it will be the same
358 as the final sender class.
359 \a slotObj the slot object
360*/
361void QTimer::singleShotImpl(std::chrono::nanoseconds ns, Qt::TimerType timerType,
362 const QObject *receiver,
363 QtPrivate::QSlotObjectBase *slotObj)
364{
365 if (ns == 0ns) {
366 bool deleteReceiver = false;
367 // Optimize: set a receiver context when none is given, such that we can use
368 // QMetaObject::invokeMethod which is more efficient than going through a timer.
369 // We need a QObject living in the current thread. But the QThread itself lives
370 // in a different thread - with the exception of the main QThread which lives in
371 // itself. And QThread::currentThread() is among the few QObjects we know that will
372 // most certainly be there. Note that one can actually call singleShot before the
373 // QApplication is created!
374 if (!receiver && QThread::currentThread() == QCoreApplicationPrivate::mainThread()) {
375 // reuse main thread as context object
376 receiver = QThread::currentThread();
377 } else if (!receiver) {
378 // Create a receiver context object on-demand. According to the benchmarks,
379 // this is still more efficient than going through a timer.
380 receiver = new QObject;
381 deleteReceiver = true;
382 }
383
384 auto h = QtPrivate::invokeMethodHelper({});
385 QMetaObject::invokeMethodImpl(const_cast<QObject *>(receiver), slotObj,
386 Qt::QueuedConnection, h.parameterCount(), h.parameters.data(), h.typeNames.data(),
387 h.metaTypes.data());
388
389 if (deleteReceiver)
390 const_cast<QObject *>(receiver)->deleteLater();
391 return;
392 }
393
394 (void) new QSingleShotTimer(ns, timerType, receiver, slotObj);
395}
396
397/*!
398 \fn void QTimer::singleShot(int msec, const QObject *receiver, const char *member)
399 \reentrant
400 \deprecated [6.8] Use the chrono overloads.
401 This static function calls a slot after a given time interval.
402
403 It is very convenient to use this function because you do not need
404 to bother with a \l{QObject::timerEvent()}{timerEvent} or
405 create a local QTimer object.
406
407 Example:
408 \snippet code/src_corelib_kernel_qtimer.cpp 0
409
410 This sample program automatically terminates after 10 minutes
411 (600,000 milliseconds).
412
413 The \a receiver is the receiving object and the \a member is the
414 slot. The time interval is \a msec milliseconds.
415
416 \include timers-common.qdocinc negative-intervals-not-allowed
417
418 \sa start()
419*/
420
421/*!
422 \fn void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiver, const char *member)
423 \overload
424 \reentrant
425 \deprecated [6.8] Use the chrono overloads.
426 This static function calls a slot after a given time interval.
427
428 It is very convenient to use this function because you do not need
429 to bother with a \l{QObject::timerEvent()}{timerEvent} or
430 create a local QTimer object.
431
432 The \a receiver is the receiving object and the \a member is the slot. The
433 time interval is \a msec milliseconds. The \a timerType affects the
434 accuracy of the timer.
435
436 \include timers-common.qdocinc negative-intervals-not-allowed
437
438 \sa start()
439*/
440
441void QTimer::singleShot(std::chrono::nanoseconds ns, Qt::TimerType timerType,
442 const QObject *receiver, const char *member)
443{
444 if (ns < 0ns) {
445 qWarning("QTimer::singleShot: negative intervals aren't allowed; the "
446 "interval will be set to 1ms.");
447 ns = 1ms;
448 }
449 if (receiver && member) {
450 if (ns == 0ns) {
451 // special code shortpath for 0-timers
452 const char* bracketPosition = strchr(member, '(');
453 if (!bracketPosition || !(member[0] >= '0' && member[0] <= '2')) {
454 qWarning("QTimer::singleShot: Invalid slot specification");
455 return;
456 }
457 const auto methodName = QByteArrayView(member + 1, // extract method name
458 bracketPosition - 1 - member).trimmed();
459 QMetaObject::invokeMethod(const_cast<QObject *>(receiver), methodName.toByteArray().constData(),
460 Qt::QueuedConnection);
461 return;
462 }
463 (void) new QSingleShotTimer(ns, timerType, receiver, member);
464 }
465}
466
467/*! \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration interval, const QObject *context, Functor &&functor)
468 \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration interval, Qt::TimerType timerType, const QObject *context, Functor &&functor)
469 \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration interval, Functor &&functor)
470 \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration interval, Qt::TimerType timerType, Functor &&functor)
471 \since 5.4
472
473 \reentrant
474 This static function calls \a functor after \a interval.
475
476 It is very convenient to use this function because you do not need
477 to bother with a \l{QObject::timerEvent()}{timerEvent} or
478 create a local QTimer object.
479
480 If \a context is specified, then the \a functor will be called only if the
481 \a context object has not been destroyed before the interval occurs. The functor
482 will then be run the thread of \a context. The context's thread must have a
483 running Qt event loop.
484
485 If \a functor is a member
486 function of \a context, then the function will be called on the object.
487
488 The \a interval parameter can be an \c int (interpreted as a millisecond
489 count) or a \c std::chrono type that implicitly converts to nanoseconds.
490
491 \include timers-common.qdocinc negative-intervals-not-allowed
492
493 \note In Qt versions prior to 6.8, the chrono overloads took chrono::milliseconds,
494 not chrono::nanoseconds. The compiler will automatically convert for you,
495 but the conversion may overflow for extremely large milliseconds counts.
496
497 \sa start()
498*/
499
500/*!
501 \fn void QTimer::singleShot(std::chrono::nanoseconds nsec, const QObject *receiver, const char *member)
502 \since 5.8
503 \overload
504 \reentrant
505
506 This static function calls a slot after a given time interval.
507
508 It is very convenient to use this function because you do not need
509 to bother with a \l{QObject::timerEvent()}{timerEvent} or
510 create a local QTimer object.
511
512 The \a receiver is the receiving object and the \a member is the slot. The
513 time interval is given in the duration object \a nsec.
514
515 \include timers-common.qdocinc negative-intervals-not-allowed
516
517//! [qtimer-ns-overflow]
518 \note In Qt versions prior to 6.8, this function took chrono::milliseconds,
519 not chrono::nanoseconds. The compiler will automatically convert for you,
520 but the conversion may overflow for extremely large milliseconds counts.
521//! [qtimer-ns-overflow]
522
523 \sa start()
524*/
525
526/*!
527 \fn void QTimer::singleShot(std::chrono::nanoseconds nsec, Qt::TimerType timerType, const QObject *receiver, const char *member)
528 \since 5.8
529 \overload
530 \reentrant
531
532 This static function calls a slot after a given time interval.
533
534 It is very convenient to use this function because you do not need
535 to bother with a \l{QObject::timerEvent()}{timerEvent} or
536 create a local QTimer object.
537
538 The \a receiver is the receiving object and the \a member is the slot. The
539 time interval is given in the duration object \a nsec. The \a timerType affects the
540 accuracy of the timer.
541
542
543 \include timers-common.qdocinc negative-intervals-not-allowed
544
545 \include qtimer.cpp qtimer-ns-overflow
546
547 \sa start()
548*/
549
550/*!
551 \fn template <typename Functor> QMetaObject::Connection QTimer::callOnTimeout(Functor &&slot)
552 \since 5.12
553
554 Creates a connection from the timer's timeout() signal to \a slot.
555 Returns a handle to the connection.
556
557 This method is provided for convenience. It's equivalent to calling:
558 \code
559 QObject::connect(timer, &QTimer::timeout, timer, slot, Qt::DirectConnection);
560 \endcode
561
562 \note This overload is not available when \c {QT_NO_CONTEXTLESS_CONNECT} is
563 defined, instead use the callOnTimeout() overload that takes a context object.
564
565 \sa QObject::connect(), timeout()
566*/
567
568/*!
569 \fn template <typename Functor> QMetaObject::Connection QTimer::callOnTimeout(const QObject *context, Functor &&slot, Qt::ConnectionType connectionType = Qt::AutoConnection)
570 \since 5.12
571 \overload callOnTimeout()
572
573 Creates a connection from the timeout() signal to \a slot to be placed in a specific
574 event loop of \a context, and returns a handle to the connection.
575
576 This method is provided for convenience. It's equivalent to calling:
577 \code
578 QObject::connect(timer, &QTimer::timeout, context, slot, connectionType);
579 \endcode
580
581 \sa QObject::connect(), timeout()
582*/
583
584/*!
585 \fn std::chrono::milliseconds QTimer::intervalAsDuration() const
586 \since 5.8
587
588 Returns the interval of this timer as a \c std::chrono::milliseconds object.
589
590 \sa interval
591*/
592
593/*!
594 \fn std::chrono::milliseconds QTimer::remainingTimeAsDuration() const
595 \since 5.8
596
597 Returns the time remaining in this timer object as a \c
598 std::chrono::milliseconds object. If this timer is due or overdue, the
599 returned value is \c std::chrono::milliseconds::zero(). If the remaining
600 time could not be found or the timer is not running, this function returns a
601 negative duration.
602
603 \sa remainingTime()
604*/
605
606/*!
607 \property QTimer::singleShot
608 \brief whether the timer is a single-shot timer
609
610 A single-shot timer fires only once, non-single-shot timers fire
611 every \l interval milliseconds.
612
613 The default value for this property is \c false.
614
615 \sa interval, singleShot()
616*/
617void QTimer::setSingleShot(bool singleShot)
618{
619 d_func()->single = singleShot;
620}
621
622bool QTimer::isSingleShot() const
623{
624 return d_func()->single;
625}
626
627QBindable<bool> QTimer::bindableSingleShot()
628{
629 return QBindable<bool>(&d_func()->single);
630}
631
632/*!
633 \property QTimer::interval
634 \brief the timeout interval in milliseconds
635
636 The default value for this property is 0. A QTimer with a timeout
637 interval of 0 will time out as soon as all the events in the window
638 system's event queue have been processed.
639
640 \include qtimer.cpp eventloop-busy
641
642 Setting the interval of a running timer will change the interval,
643 stop() and then start() the timer, and acquire a new id().
644 If the timer is not running, only the interval is changed.
645
646 \include timers-common.qdocinc negative-intervals-not-allowed
647
648 \sa singleShot
649*/
650void QTimer::setInterval(int msec)
651{
652 setInterval(std::chrono::milliseconds{msec});
653}
654
655void QTimer::setInterval(std::chrono::milliseconds interval)
656{
657 Q_D(QTimer);
658
659 interval = checkInterval("QTimer::setInterval", interval);
660 const int msec = interval.count();
661 d->inter.removeBindingUnlessInWrapper();
662 const bool intervalChanged = msec != d->inter.valueBypassingBindings();
663 d->inter.setValueBypassingBindings(msec);
664 if (d->isActive()) { // create new timer
665 QObject::killTimer(d->id); // restart timer
666 Qt::TimerId newId{ QObject::startTimer(msec * 1ms, d->type) }; // overflow impossible
667 if (newId > Qt::TimerId::Invalid) {
668 // Restarted successfully. No need to update the active state.
669 d->id = newId;
670 } else {
671 // Failed to start the timer.
672 // Need to notify about active state change.
673 d->id = Qt::TimerId::Invalid;
674 d->isActiveData.notify();
675 }
676 }
677 if (intervalChanged)
678 d->inter.notify();
679}
680
681int QTimer::interval() const
682{
683 return d_func()->inter;
684}
685
686QBindable<int> QTimer::bindableInterval()
687{
688 return QBindable<int>(&d_func()->inter);
689}
690
691/*!
692 \property QTimer::remainingTime
693 \since 5.0
694 \brief the remaining time in milliseconds
695
696 Returns the timer's remaining value in milliseconds left until the timeout.
697 If the timer is inactive, the returned value will be -1. If the timer is
698 overdue, the returned value will be 0.
699
700 \sa interval
701*/
702int QTimer::remainingTime() const
703{
704 Q_D(const QTimer);
705 if (d->isActive()) {
706 using namespace std::chrono;
707 auto remaining = QAbstractEventDispatcher::instance()->remainingTime(d->id);
708 return ceil<milliseconds>(remaining).count();
709 }
710
711 return -1;
712}
713
714/*!
715 \property QTimer::timerType
716 \brief controls the accuracy of the timer
717
718 The default value for this property is \c Qt::CoarseTimer.
719
720 \sa Qt::TimerType
721*/
722void QTimer::setTimerType(Qt::TimerType atype)
723{
724 d_func()->type = atype;
725}
726
727Qt::TimerType QTimer::timerType() const
728{
729 return d_func()->type;
730}
731
732QBindable<Qt::TimerType> QTimer::bindableTimerType()
733{
734 return QBindable<Qt::TimerType>(&d_func()->type);
735}
736
737QT_END_NAMESPACE
738
739#include "moc_qtimer.cpp"
~QTimerPrivate() override
static std::chrono::milliseconds checkInterval(const char *caller, std::chrono::milliseconds interval)
Definition qtimer.cpp:252