c++qtqt5qtimerqstatemachine

Explanation about QStateMachine delay function


I used this function in my program:

void delay(QState * state1, int millisecond, QAbstractState * state2) 
{
   auto timer = new QTimer(state1);
   timer->setSingleShot(true);
   timer->setInterval(millisecond);

   QObject::connect(state1, &QState::entered, timer, static_cast<void (QTimer::*)()>(&QTimer::start));
   QObject::connect(state1, &QState::exited,  timer, &QTimer::stop);

   state1 -> addTransition(timer, SIGNAL(timeout()), state2);
}

I made a copy-paste from an example and I did not understand this part of code:

QObject::connect(state1,..., static_cast<void (QTimer::*)()>(&QTimer::start));

Anyone can explain to me what this code is ? How it works in the program ?

PS. I tried to change that code with this but it didn't work:

QTimer *timer = new QTimer(state1);
.
.  //same code as before
.
QObject::connect(stato1,&QState::entered,timer,[&] {timer->start();} );
QObject::connect(stato1,&QState::exited, timer,[&] {timer->stop(); } );

stato1 -> addTransition(timer,SIGNAL(timeout()),stato2);

Solution

  • There are two QTimer::start slots, one without parameters and one with int msec parameter. To connect to the correct one with the new connect syntax, you must specify the slot type with a static_cast.

    So in this line:

    QObject::connect(state1, &QState::entered, timer, static_cast<void (QTimer::*)()>(&QTimer::start));
    

    You connect to QTimer::start slot which takes no arguments.

    If you had a signal with an int parameter and you wanted to connect to QTimer::start(int msec) slot, you'd do it like this:

    connect(this, &MyClass::mySignal, timer, static_cast<void (QTimer::*)(int)>(&QTimer::start));
    

    You can read more about using overloaded signals/slots with the new connect syntax here.

    You can also use qOverload to remove the need of the ugly static_cast.

    In the snippet where you use lambda expressions, you capture timer by reference. You should capture it by value instead:

    QObject::connect(stato1, &QState::entered, timer, [=]{timer->start();});