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) <ogoffart@woboq.com>
This commit is contained in:
Sergio Martins 2018-03-05 22:54:57 +00:00 committed by Sérgio Martins
parent 863c688749
commit a6d1456458
3 changed files with 82 additions and 0 deletions

View File

@ -570,6 +570,48 @@ void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiv
\sa start() \sa start()
*/ */
/*!
\fn template<typename Functor> 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<typename Functor> 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<typename PointerToMemberFunction> 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) \fn void QTimer::start(std::chrono::milliseconds msec)
\since 5.8 \since 5.8

View File

@ -96,6 +96,12 @@ public:
static void singleShot(int msec, const QObject *context, Functor functor); static void singleShot(int msec, const QObject *context, Functor functor);
template<typename Functor, int> template<typename Functor, int>
static void singleShot(int msec, Qt::TimerType timerType, const QObject *context, Functor functor); static void singleShot(int msec, Qt::TimerType timerType, const QObject *context, Functor functor);
template <typename Functor>
QMetaObject::Connection connectTo(Functor slot, Qt::ConnectionType connectionType = Qt::AutoConnection);
template <typename Functor>
QMetaObject::Connection connectTo(const QObject *context, Functor slot, Qt::ConnectionType connectionType = Qt::AutoConnection);
template <typename PointerToMemberFunction>
QMetaObject::Connection connectTo(const QObject *receiver, PointerToMemberFunction slot, Qt::ConnectionType connectionType = Qt::AutoConnection);
#else #else
// singleShot to a QObject slot // singleShot to a QObject slot
template <typename Duration, typename Func1> template <typename Duration, typename Func1>
@ -152,6 +158,13 @@ public:
new QtPrivate::QFunctorSlotObject<Func1, 0, new QtPrivate::QFunctorSlotObject<Func1, 0,
typename QtPrivate::List_Left<void, 0>::Value, void>(std::move(slot))); typename QtPrivate::List_Left<void, 0>::Value, void>(std::move(slot)));
} }
template <typename ... Args>
QMetaObject::Connection connectTo(Args && ...args)
{
return QObject::connect(this, &QTimer::timeout, std::forward<Args>(args)... );
}
#endif #endif
public Q_SLOTS: public Q_SLOTS:

View File

@ -75,6 +75,7 @@ private slots:
void dontBlockEvents(); void dontBlockEvents();
void postedEventsShouldNotStarveTimers(); void postedEventsShouldNotStarveTimers();
void connectTo();
}; };
class TimerHelper : public QObject class TimerHelper : public QObject
@ -1020,5 +1021,31 @@ void tst_QTimer::crossThreadSingleShotToFunctor()
delete o; 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) QTEST_MAIN(tst_QTimer)
#include "tst_qtimer.moc" #include "tst_qtimer.moc"