jpo38
jpo38

Reputation: 21514

Qt: waiting for a signal with timeout management

I'm looking for a simple way to wait for an object to emit signal with timeout management using Qt.

Is there an easy way to do that using Qt classes?

Here is an example of application:

QLowEnergyController controller(remoteDevice);
controller.connectToDevice();
// now wait for controller to emit connected() with a 1sec timeout

Upvotes: 1

Views: 3507

Answers (2)

ForgottenUmbrella
ForgottenUmbrella

Reputation: 1110

In Qt 5, the QtTest header has QSignalSpy::wait, to wait until a signal is emitted or a timeout (in milliseconds) occurs.

auto controller = QLowEnergyController{remoteDevice};
auto spy = QSignalSpy{*controller, SIGNAL(connected())};
controller.connectToDevice();
spy.wait(1000);

Upvotes: 2

jpo38
jpo38

Reputation: 21514

Based on this post, here is a class (encapsulating @EnOpenUK solution) and proposing a wait function with timeout management.

Header file:

#include <QEventLoop>
class WaitForSignalHelper : public QObject
{
    Q_OBJECT
public:
    WaitForSignalHelper( QObject& object, const char* signal );

    // return false if signal wait timed-out
    bool wait();

public slots:
    void timeout( int timeoutMs );

private:
    bool m_bTimeout;
    QEventLoop m_eventLoop;
};

Implementation file:

#include <QTimer>
WaitForSignalHelper::WaitForSignalHelper( QObject& object, const char* signal ) : 
    m_bTimeout( false )
{
    connect(&object, signal, &m_eventLoop, SLOT(quit()));
}

bool WaitForSignalHelper::wait( int timeoutMs )
{
    QTimer timeoutHelper;
    if ( timeoutMs != 0 ) // manage timeout
    {
        timeoutHelper.setInterval( timeoutMs );
        timeoutHelper.start();
        connect(&timeoutHelper, SIGNAL(timeout()), this, SLOT(timeout()));
    }
    // else, wait for ever!

    m_bTimeout = false;

    m_eventLoop.exec();

    return !m_bTimeout;
}

void WaitForSignalHelper::timeout()
{
    m_bTimeout = true;
    m_eventLoop.quit();
}

Example:

QLowEnergyController controller(remoteDevice);
controller.connectToDevice();
WaitForSignalHelper helper( controller, SIGNAL(connected()) );
if ( helper.wait( 1000 ) )
    std::cout << "Signal was received" << std::endl; 
else
    std::cout << "Signal was not received after 1sec" << std::endl;

Note that setting timeout parameter to 0 makes the object wait for ever...could be useful.

Upvotes: 3

Related Questions