QTimer: add support for <chrono> functions
[ChangeLog][QtCore][QTimer] Added support for std::chrono duration objects for QTimer methods, like QTimer::singleShot and QTimer::setInterval. Change-Id: I87e17314d8b24ae983b1fffd14536e24d5b12424 Reviewed-by: Marc Mutz <marc.mutz@kdab.com>bb10
parent
b2c0f9713c
commit
d16ba63f5c
|
|
@ -532,6 +532,78 @@ void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiv
|
|||
\sa start()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void QTimer::singleShot(std::chrono::duration<Rep, Period> value, const QObject *receiver, const char *member)
|
||||
\since 5.8
|
||||
\overload
|
||||
\reentrant
|
||||
|
||||
This static function calls a slot after a given time interval.
|
||||
|
||||
It is very convenient to use this function because you do not need
|
||||
to bother with a \l{QObject::timerEvent()}{timerEvent} or
|
||||
create a local QTimer object.
|
||||
|
||||
The \a receiver is the receiving object and the \a member is the slot. The
|
||||
time interval is given in the duration object \a value.
|
||||
|
||||
\sa start()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void QTimer::singleShot(std::chrono::duration<Rep, Period> value, Qt::TimerType timerType, const QObject *receiver, const char *member)
|
||||
\since 5.8
|
||||
\overload
|
||||
\reentrant
|
||||
|
||||
This static function calls a slot after a given time interval.
|
||||
|
||||
It is very convenient to use this function because you do not need
|
||||
to bother with a \l{QObject::timerEvent()}{timerEvent} or
|
||||
create a local QTimer object.
|
||||
|
||||
The \a receiver is the receiving object and the \a member is the slot. The
|
||||
time interval is given in the duration object \a value. The \a timerType affects the
|
||||
accuracy of the timer.
|
||||
|
||||
\sa start()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void QTimer::start(std::chrono::duration<Rep, Period> value)
|
||||
\since 5.8
|
||||
\overload
|
||||
|
||||
Starts or restarts the timer with a timeout of duration \a value.
|
||||
|
||||
If the timer is already running, it will be
|
||||
\l{QTimer::stop()}{stopped} and restarted.
|
||||
|
||||
If \l singleShot is true, the timer will be activated only once.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn std::chrono::milliseconds QTimer::intervalAsDuration() const
|
||||
\since 5.8
|
||||
|
||||
Returns the interval of this timer as a \c std::chrono::milliseconds object.
|
||||
|
||||
\sa interval
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn std::chrono::milliseconds QTimer::remainingTimeAsDuration() const
|
||||
\since 5.8
|
||||
|
||||
Returns the time remaining in this timer object as a \c
|
||||
std::chrono::milliseconds object. If this timer is due or overdue, the
|
||||
returned value is \c std::chrono::milliseconds::zero(). If the remaining
|
||||
time could not be found or the timer is not active, this function returns a
|
||||
negative duration.
|
||||
|
||||
\sa remainingTime()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\property QTimer::singleShot
|
||||
\brief whether the timer is a single-shot timer
|
||||
|
|
|
|||
|
|
@ -47,6 +47,10 @@
|
|||
#include <QtCore/qbasictimer.h> // conceptual inheritance
|
||||
#include <QtCore/qobject.h>
|
||||
|
||||
#if QT_HAS_INCLUDE(<chrono>)
|
||||
# include <chrono>
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
||||
|
|
@ -94,13 +98,13 @@ public:
|
|||
static void singleShot(int msec, Qt::TimerType timerType, const QObject *context, Functor functor);
|
||||
#else
|
||||
// singleShot to a QObject slot
|
||||
template <typename Func1>
|
||||
static inline void singleShot(int msec, const typename QtPrivate::FunctionPointer<Func1>::Object *receiver, Func1 slot)
|
||||
template <typename Duration, typename Func1>
|
||||
static inline void singleShot(Duration interval, const typename QtPrivate::FunctionPointer<Func1>::Object *receiver, Func1 slot)
|
||||
{
|
||||
singleShot(msec, msec >= 2000 ? Qt::CoarseTimer : Qt::PreciseTimer, receiver, slot);
|
||||
singleShot(interval, defaultTypeFor(interval), receiver, slot);
|
||||
}
|
||||
template <typename Func1>
|
||||
static inline void singleShot(int msec, Qt::TimerType timerType, const typename QtPrivate::FunctionPointer<Func1>::Object *receiver,
|
||||
template <typename Duration, typename Func1>
|
||||
static inline void singleShot(Duration interval, Qt::TimerType timerType, const typename QtPrivate::FunctionPointer<Func1>::Object *receiver,
|
||||
Func1 slot)
|
||||
{
|
||||
typedef QtPrivate::FunctionPointer<Func1> SlotType;
|
||||
|
|
@ -109,42 +113,42 @@ public:
|
|||
Q_STATIC_ASSERT_X(int(SlotType::ArgumentCount) == 0,
|
||||
"The slot must not have any arguments.");
|
||||
|
||||
singleShotImpl(msec, timerType, receiver,
|
||||
singleShotImpl(interval, timerType, receiver,
|
||||
new QtPrivate::QSlotObject<Func1, typename SlotType::Arguments, void>(slot));
|
||||
}
|
||||
// singleShot to a functor or function pointer (without context)
|
||||
template <typename Func1>
|
||||
template <typename Duration, typename Func1>
|
||||
static inline typename QtPrivate::QEnableIf<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
|
||||
!QtPrivate::is_same<const char*, Func1>::value, void>::Type
|
||||
singleShot(int msec, Func1 slot)
|
||||
singleShot(Duration interval, Func1 slot)
|
||||
{
|
||||
singleShot(msec, msec >= 2000 ? Qt::CoarseTimer : Qt::PreciseTimer, Q_NULLPTR, slot);
|
||||
singleShot(interval, defaultTypeFor(interval), nullptr, slot);
|
||||
}
|
||||
template <typename Func1>
|
||||
template <typename Duration, typename Func1>
|
||||
static inline typename QtPrivate::QEnableIf<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
|
||||
!QtPrivate::is_same<const char*, Func1>::value, void>::Type
|
||||
singleShot(int msec, Qt::TimerType timerType, Func1 slot)
|
||||
singleShot(Duration interval, Qt::TimerType timerType, Func1 slot)
|
||||
{
|
||||
singleShot(msec, timerType, Q_NULLPTR, slot);
|
||||
singleShot(interval, timerType, nullptr, slot);
|
||||
}
|
||||
// singleShot to a functor or function pointer (with context)
|
||||
template <typename Func1>
|
||||
template <typename Duration, typename Func1>
|
||||
static inline typename QtPrivate::QEnableIf<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
|
||||
!QtPrivate::is_same<const char*, Func1>::value, void>::Type
|
||||
singleShot(int msec, QObject *context, Func1 slot)
|
||||
singleShot(Duration interval, QObject *context, Func1 slot)
|
||||
{
|
||||
singleShot(msec, msec >= 2000 ? Qt::CoarseTimer : Qt::PreciseTimer, context, slot);
|
||||
singleShot(interval, defaultTypeFor(interval), context, slot);
|
||||
}
|
||||
template <typename Func1>
|
||||
template <typename Duration, typename Func1>
|
||||
static inline typename QtPrivate::QEnableIf<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
|
||||
!QtPrivate::is_same<const char*, Func1>::value, void>::Type
|
||||
singleShot(int msec, Qt::TimerType timerType, QObject *context, Func1 slot)
|
||||
singleShot(Duration interval, Qt::TimerType timerType, QObject *context, Func1 slot)
|
||||
{
|
||||
//compilation error if the slot has arguments.
|
||||
typedef QtPrivate::FunctionPointer<Func1> SlotType;
|
||||
Q_STATIC_ASSERT_X(int(SlotType::ArgumentCount) <= 0, "The slot must not have any arguments.");
|
||||
|
||||
singleShotImpl(msec, timerType, context,
|
||||
singleShotImpl(interval, timerType, context,
|
||||
new QtPrivate::QFunctorSlotObject<Func1, 0,
|
||||
typename QtPrivate::List_Left<void, 0>::Value, void>(slot));
|
||||
}
|
||||
|
|
@ -159,6 +163,43 @@ public Q_SLOTS:
|
|||
Q_SIGNALS:
|
||||
void timeout(QPrivateSignal);
|
||||
|
||||
public:
|
||||
#if QT_HAS_INCLUDE(<chrono>) || defined(Q_QDOC)
|
||||
template <class Rep, class Period>
|
||||
void setInterval(std::chrono::duration<Rep, Period> value)
|
||||
{
|
||||
setInterval(std::chrono::duration_cast<std::chrono::milliseconds>(value).count());
|
||||
}
|
||||
|
||||
std::chrono::milliseconds intervalAsDuration() const
|
||||
{
|
||||
return std::chrono::milliseconds(interval());
|
||||
}
|
||||
|
||||
std::chrono::milliseconds remainingTimeAsDuration() const
|
||||
{
|
||||
return std::chrono::milliseconds(remainingTime());
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
static void singleShot(std::chrono::duration<Rep, Period> value, const QObject *receiver, const char *member)
|
||||
{
|
||||
singleShot(int(std::chrono::duration_cast<std::chrono::milliseconds>(value).count()), receiver, member);
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
static void singleShot(std::chrono::duration<Rep, Period> value, Qt::TimerType timerType, const QObject *receiver, const char *member)
|
||||
{
|
||||
singleShot(int(std::chrono::duration_cast<std::chrono::milliseconds>(value).count()), timerType, receiver, member);
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
void start(std::chrono::duration<Rep, Period> value)
|
||||
{
|
||||
start(int(std::chrono::duration_cast<std::chrono::milliseconds>(value).count()));
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent *) Q_DECL_OVERRIDE;
|
||||
|
||||
|
|
@ -168,9 +209,25 @@ private:
|
|||
inline int startTimer(int){ return -1;}
|
||||
inline void killTimer(int){}
|
||||
|
||||
static Q_DECL_CONSTEXPR Qt::TimerType defaultTypeFor(int msecs) Q_DECL_NOTHROW
|
||||
{ return msecs >= 2000 ? Qt::CoarseTimer : Qt::PreciseTimer; }
|
||||
static void singleShotImpl(int msec, Qt::TimerType timerType,
|
||||
const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj);
|
||||
|
||||
#if QT_HAS_INCLUDE(<chrono>)
|
||||
template <class Rep, class Period>
|
||||
static Qt::TimerType defaultTypeFor(std::chrono::duration<Rep, Period> interval)
|
||||
{ return defaultTypeFor(int(std::chrono::duration_cast<std::chrono::milliseconds>(interval).count())); }
|
||||
|
||||
template <class Rep, class Period>
|
||||
static void singleShotImpl(std::chrono::duration<Rep, Period> interval, Qt::TimerType timerType,
|
||||
const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj)
|
||||
{
|
||||
singleShotImpl(int(std::chrono::duration_cast<std::chrono::milliseconds>(interval).count()),
|
||||
timerType, receiver, slotObj);
|
||||
}
|
||||
#endif
|
||||
|
||||
int id, inter, del;
|
||||
uint single : 1;
|
||||
uint nulltimer : 1;
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ private slots:
|
|||
void remainingTime();
|
||||
void remainingTimeDuringActivation_data();
|
||||
void remainingTimeDuringActivation();
|
||||
void basic_chrono();
|
||||
void livelock_data();
|
||||
void livelock();
|
||||
void timerInfiniteRecursion_data();
|
||||
|
|
@ -68,6 +69,7 @@ private slots:
|
|||
void singleShotStaticFunctionZeroTimeout();
|
||||
void recurseOnTimeoutAndStopTimer();
|
||||
void singleShotToFunctors();
|
||||
void singleShot_chrono();
|
||||
void crossThreadSingleShotToFunctor();
|
||||
|
||||
void dontBlockEvents();
|
||||
|
|
@ -214,6 +216,57 @@ void tst_QTimer::remainingTimeDuringActivation()
|
|||
}
|
||||
}
|
||||
|
||||
void tst_QTimer::basic_chrono()
|
||||
{
|
||||
#if !QT_HAS_INCLUDE(<chrono>)
|
||||
QSKIP("This test requires C++11 <chrono> support");
|
||||
#else
|
||||
// duplicates zeroTimer, singleShotTimeout, interval and remainingTime
|
||||
using namespace std::chrono;
|
||||
TimerHelper helper;
|
||||
QTimer timer;
|
||||
timer.setInterval(nanoseconds(0));
|
||||
timer.start();
|
||||
QCOMPARE(timer.intervalAsDuration().count(), milliseconds::rep(0));
|
||||
QCOMPARE(timer.remainingTimeAsDuration().count(), milliseconds::rep(0));
|
||||
|
||||
connect(&timer, SIGNAL(timeout()), &helper, SLOT(timeout()));
|
||||
|
||||
QCoreApplication::processEvents();
|
||||
|
||||
QCOMPARE(helper.count, 1);
|
||||
|
||||
helper.count = 0;
|
||||
timer.start(milliseconds(100));
|
||||
QCOMPARE(helper.count, 0);
|
||||
|
||||
QTest::qWait(TIMEOUT_TIMEOUT);
|
||||
QVERIFY(helper.count > 0);
|
||||
int oldCount = helper.count;
|
||||
|
||||
QTest::qWait(TIMEOUT_TIMEOUT);
|
||||
QVERIFY(helper.count > oldCount);
|
||||
|
||||
helper.count = 0;
|
||||
timer.start(microseconds(200000));
|
||||
QCOMPARE(timer.intervalAsDuration().count(), milliseconds::rep(200));
|
||||
QTest::qWait(50);
|
||||
QCOMPARE(helper.count, 0);
|
||||
|
||||
milliseconds rt = timer.remainingTimeAsDuration();
|
||||
QVERIFY2(qAbs(rt.count() - 150) < 50, qPrintable(QString::number(rt.count())));
|
||||
|
||||
helper.count = 0;
|
||||
timer.setSingleShot(true);
|
||||
timer.start(milliseconds(100));
|
||||
QTest::qWait(500);
|
||||
QCOMPARE(helper.count, 1);
|
||||
QTest::qWait(500);
|
||||
QCOMPARE(helper.count, 1);
|
||||
helper.count = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void tst_QTimer::livelock_data()
|
||||
{
|
||||
QTest::addColumn<int>("interval");
|
||||
|
|
@ -787,6 +840,51 @@ void tst_QTimer::singleShotToFunctors()
|
|||
_t = Q_NULLPTR;
|
||||
}
|
||||
|
||||
void tst_QTimer::singleShot_chrono()
|
||||
{
|
||||
#if !QT_HAS_INCLUDE(<chrono>)
|
||||
QSKIP("This test requires C++11 <chrono> support");
|
||||
#else
|
||||
// duplicates singleShotStaticFunctionZeroTimeout and singleShotToFunctors
|
||||
using namespace std::chrono;
|
||||
TimerHelper helper;
|
||||
|
||||
QTimer::singleShot(hours(0), &helper, SLOT(timeout()));
|
||||
QTest::qWait(500);
|
||||
QCOMPARE(helper.count, 1);
|
||||
QTest::qWait(500);
|
||||
QCOMPARE(helper.count, 1);
|
||||
|
||||
TimerHelper nhelper;
|
||||
|
||||
QTimer::singleShot(seconds(0), &nhelper, &TimerHelper::timeout);
|
||||
QCoreApplication::processEvents();
|
||||
QCOMPARE(nhelper.count, 1);
|
||||
QCoreApplication::processEvents();
|
||||
QCOMPARE(nhelper.count, 1);
|
||||
|
||||
int count = 0;
|
||||
QTimer::singleShot(microseconds(0), CountedStruct(&count));
|
||||
QCoreApplication::processEvents();
|
||||
QCOMPARE(count, 1);
|
||||
|
||||
_e.reset(new QEventLoop);
|
||||
QTimer::singleShot(0, &StaticEventLoop::quitEventLoop);
|
||||
QCOMPARE(_e->exec(), 0);
|
||||
|
||||
QObject c3;
|
||||
QTimer::singleShot(milliseconds(500), &c3, CountedStruct(&count));
|
||||
QTest::qWait(800);
|
||||
QCOMPARE(count, 2);
|
||||
|
||||
QTimer::singleShot(0, [&count] { ++count; });
|
||||
QCoreApplication::processEvents();
|
||||
QCOMPARE(count, 3);
|
||||
|
||||
_e.reset();
|
||||
#endif
|
||||
}
|
||||
|
||||
class DontBlockEvents : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
|
|||
Loading…
Reference in New Issue