From a6d1456458b6e19c850adadb1a81c4a9acbdbe92 Mon Sep 17 00:00:00 2001 From: Sergio Martins Date: Mon, 5 Mar 2018 22:54:57 +0000 Subject: [PATCH] Add QTimer::connectTo(), a shorthand way of connecting to timeout() There are a couple of Qt classes where you almost always use the same signal, for example QTimer::timeout, QPushButton::clicked, and QAction::triggered. Simply doing timer.connectTo([]{}) is much more convenient, less tedious and even fun. Not overloading connect() as it would be confusing to see the receiver as first argument. And not naming it onTimeout, as that's a popular way of doing it in other frameworks. People would assume you could use on* with any signal. If we ever have on* it should be all or nothing. [ChangeLog][QtCore] Added QTimer::connectTo(), a shorthand way of connecting to the timeout() signal. Change-Id: Ida57e5442b13d50972ed585c3ea7be07e3d8e8d2 Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/corelib/kernel/qtimer.cpp | 42 +++++++++++++++++++ src/corelib/kernel/qtimer.h | 13 ++++++ .../auto/corelib/kernel/qtimer/tst_qtimer.cpp | 27 ++++++++++++ 3 files changed, 82 insertions(+) diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp index c3504943c4..802c8d72f6 100644 --- a/src/corelib/kernel/qtimer.cpp +++ b/src/corelib/kernel/qtimer.cpp @@ -570,6 +570,48 @@ void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiv \sa start() */ +/*! + \fn template QMetaObject::Connection connectTo(Functor functor, Qt::ConnectionType connectionType = Qt::AutoConnection) + \since 5.12 + \overload + + Creates a connection from the timeout() signal to \a functor, and returns a + handle to the connection. + + This method is provided for convenience. + It's equivalent to calling \c {QObject::connect(timer, &QTimer::timeout, timer, functor, connectionType)}. + + \sa QObject::connect(), timeout() +*/ + +/*! + \fn template QMetaObject::Connection connectTo(QObject *context, Functor functor, Qt::ConnectionType connectionType = Qt::AutoConnection) + \since 5.12 + \overload connectTo() + + Creates a connection from the timeout() signal to \a functor to be placed in a specific + event loop of \a context, and returns a handle to the connection. + + This method is provided for convenience. It's equivalent to calling + \c {QObject::connect(timer, &QTimer::timeout, context, functor, connectionType)}. + + \sa QObject::connect(), timeout() +*/ + +/*! + \fn template QMetaObject::Connection connectTo(QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType connectionType = Qt::AutoConnection) + \since 5.12 + \overload connectTo() + + Creates a connection from the timeout() signal to the \a method in the \a receiver object. Returns + a handle to the connection. + + This method is provided for convenience. It's equivalent to calling + \c {QObject::connect(timer, &QTimer::timeout, receiver, method, connectionType)}. + + \sa QObject::connect(), timeout() +*/ + /*! \fn void QTimer::start(std::chrono::milliseconds msec) \since 5.8 diff --git a/src/corelib/kernel/qtimer.h b/src/corelib/kernel/qtimer.h index e6db586aa0..7825bb0798 100644 --- a/src/corelib/kernel/qtimer.h +++ b/src/corelib/kernel/qtimer.h @@ -96,6 +96,12 @@ public: static void singleShot(int msec, const QObject *context, Functor functor); template static void singleShot(int msec, Qt::TimerType timerType, const QObject *context, Functor functor); + template + QMetaObject::Connection connectTo(Functor slot, Qt::ConnectionType connectionType = Qt::AutoConnection); + template + QMetaObject::Connection connectTo(const QObject *context, Functor slot, Qt::ConnectionType connectionType = Qt::AutoConnection); + template + QMetaObject::Connection connectTo(const QObject *receiver, PointerToMemberFunction slot, Qt::ConnectionType connectionType = Qt::AutoConnection); #else // singleShot to a QObject slot template @@ -152,6 +158,13 @@ public: new QtPrivate::QFunctorSlotObject::Value, void>(std::move(slot))); } + + template + QMetaObject::Connection connectTo(Args && ...args) + { + return QObject::connect(this, &QTimer::timeout, std::forward(args)... ); + } + #endif public Q_SLOTS: diff --git a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp index 2c6d9ea7c0..2d34aceab8 100644 --- a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp +++ b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp @@ -75,6 +75,7 @@ private slots: void dontBlockEvents(); void postedEventsShouldNotStarveTimers(); + void connectTo(); }; class TimerHelper : public QObject @@ -1020,5 +1021,31 @@ void tst_QTimer::crossThreadSingleShotToFunctor() delete o; } +void tst_QTimer::connectTo() +{ + QTimer timer; + TimerHelper timerHelper; + timer.setInterval(0); + timer.start(); + + auto context = new QObject(); + + int count = 0; + timer.connectTo([&count] { count++; }); + QMetaObject::Connection connection = timer.connectTo(context, [&count] { count++; }); + timer.connectTo(&timerHelper, &TimerHelper::timeout); + timer.connectTo(&timer, &QTimer::stop); + + + QTest::qWait(100); + QCOMPARE(count, 2); + QCOMPARE(timerHelper.count, 1); + + // Test that connection is bound to context lifetime + QVERIFY(connection); + delete context; + QVERIFY(!connection); +} + QTEST_MAIN(tst_QTimer) #include "tst_qtimer.moc"