QTimer inside a for loop
-
Dear all
I'm new to QT and face some problems with Qtimer.
I want to have a loop that in each iteration sends a packet with a serial port.
There is a problem with Qtimer inside the loop since it only works for the last iteration and just sends the last packet through serialport?
what can I do to fix it?
here is the for loop:
for(int i=1;i<5;i++)
{
send[2]=LightState(i);
connect(timer, SIGNAL(timeout()), this, SLOT(senddata()));
timer->setSingleShot(true);
timer->start(timestate[i]);
}
void Trafficlight::senddata()
{
if(serialport->isOpen()){
serialport->write(send);
qDebug() <<"sending data:"<<send.toHex();
}else{
qDebug() <<"Port is not open, data:" << send.toHex();
}
} -
Dear all
I'm new to QT and face some problems with Qtimer.
I want to have a loop that in each iteration sends a packet with a serial port.
There is a problem with Qtimer inside the loop since it only works for the last iteration and just sends the last packet through serialport?
what can I do to fix it?
here is the for loop:
for(int i=1;i<5;i++)
{
send[2]=LightState(i);
connect(timer, SIGNAL(timeout()), this, SLOT(senddata()));
timer->setSingleShot(true);
timer->start(timestate[i]);
}
void Trafficlight::senddata()
{
if(serialport->isOpen()){
serialport->write(send);
qDebug() <<"sending data:"<<send.toHex();
}else{
qDebug() <<"Port is not open, data:" << send.toHex();
}
}@n_moosavi
Hello and welcome.You have a single
timerinstance, and youstart(timestate[i]);it 4 times with a differenttimestate[i]each time. This will end up with just the onetimerstarted on the finaltimestate[i]value.It is hard to know what you are wanting to achieve here. Do you want 4 distinct
QTimers for each of thetimestate[i]values? Does each timer want to count its time (delay) from when the first one was started, or does eachtimestatevalue want to count/delay from when the previous one timed out? -
@n_moosavi
Hello and welcome.You have a single
timerinstance, and youstart(timestate[i]);it 4 times with a differenttimestate[i]each time. This will end up with just the onetimerstarted on the finaltimestate[i]value.It is hard to know what you are wanting to achieve here. Do you want 4 distinct
QTimers for each of thetimestate[i]values? Does each timer want to count its time (delay) from when the first one was started, or does eachtimestatevalue want to count/delay from when the previous one timed out? -
@JonB Thanks for your reply.
Actually i want a timer that for example after 1000s sends 1, then after 2000s from when the first one was started, sends2.
so the timestate is [1000, 2000,3000,4000] and the packet is [1 2 3 4].@n_moosavi
So you can implement in one of two ways, as you choose:-
Create 4 separate
QTimer(singleshot) instances, all connected to samesenddata()slot, each one with each of the timeout durations in yourtimestatearray. -
Create one
QTimer(singleshot). Keep a member variable to count throughtimestateso you know where you have got to. On the timeout, apart from doing thesendata(), advance the counter, if it's not at end calculate the difference between the value intimestatefor this time's value and the previous one, re-load the singleQTimerinstance with that (all would be1000given the values you presently show intimestate).
-
-
@n_moosavi
So you can implement in one of two ways, as you choose:-
Create 4 separate
QTimer(singleshot) instances, all connected to samesenddata()slot, each one with each of the timeout durations in yourtimestatearray. -
Create one
QTimer(singleshot). Keep a member variable to count throughtimestateso you know where you have got to. On the timeout, apart from doing thesendata(), advance the counter, if it's not at end calculate the difference between the value intimestatefor this time's value and the previous one, re-load the singleQTimerinstance with that (all would be1000given the values you presently show intimestate).
@JonB For the first way. I tried as follows. I have created 3 separate QTimer:{timer,timerr,timerrr}
.But still, only the last timer works and sends data.timer = new QTimer(this); send=1; connect(timer, SIGNAL(timeout()), this, SLOT(senddata())); timer->setSingleShot(true); timer->start(timestate[0]); timerr = new QTimer(this); send=2; connect(timerr, SIGNAL(timeout()), this, SLOT(senddata())); timerr->setSingleShot(true); timerr->start(timestate[1]); timerrr = new QTimer(this); send=3; connect(timerrr, SIGNAL(timeout()), this, SLOT(senddata())); timerrr->setSingleShot(true); timerrr->start(timestate[2]); -
-
@JonB For the first way. I tried as follows. I have created 3 separate QTimer:{timer,timerr,timerrr}
.But still, only the last timer works and sends data.timer = new QTimer(this); send=1; connect(timer, SIGNAL(timeout()), this, SLOT(senddata())); timer->setSingleShot(true); timer->start(timestate[0]); timerr = new QTimer(this); send=2; connect(timerr, SIGNAL(timeout()), this, SLOT(senddata())); timerr->setSingleShot(true); timerr->start(timestate[1]); timerrr = new QTimer(this); send=3; connect(timerrr, SIGNAL(timeout()), this, SLOT(senddata())); timerrr->setSingleShot(true); timerrr->start(timestate[2]);@n_moosavi
These should work. PutqDebug() << "senddata()";as the first statement insenddata()and see how many times it outputs. -
@JonB For the first way. I tried as follows. I have created 3 separate QTimer:{timer,timerr,timerrr}
.But still, only the last timer works and sends data.timer = new QTimer(this); send=1; connect(timer, SIGNAL(timeout()), this, SLOT(senddata())); timer->setSingleShot(true); timer->start(timestate[0]); timerr = new QTimer(this); send=2; connect(timerr, SIGNAL(timeout()), this, SLOT(senddata())); timerr->setSingleShot(true); timerr->start(timestate[1]); timerrr = new QTimer(this); send=3; connect(timerrr, SIGNAL(timeout()), this, SLOT(senddata())); timerrr->setSingleShot(true); timerrr->start(timestate[2]);QTimer as a counter using dynamic property:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { auto* timer=new QTimer; timer->setProperty("count",5); connect(timer,&QTimer::timeout,this, &MainWindow::timeout); timer->start(1000); } void MainWindow::timeout() { QTimer* timer=qobject_cast<QTimer*>(sender()); if(timer==nullptr) return; // error wrong sender int count=timer->property("count").toInt()-1; timer->setProperty("count",count); qDebug()<<__FUNCTION__<<count; // call sendData() here if(count<=0) { timer->stop(); delete timer; } } -
@n_moosavi
These should work. PutqDebug() << "senddata()";as the first statement insenddata()and see how many times it outputs.@JonB Dear JohB.
I added the qDebug() << "senddata()"; to the senddata. Then i run
It outputs 3 times and each time with the last packet. It sends the last packet 3 times.
I tested it with switch/case but it still sends the last packet .
for (int i = 0; i < 4; i++)
{
switch(timestate[i]) {
case 1000:
send[2]=LightState(0);
connect(timer, SIGNAL(timeout()), this, SLOT(senddata()));
timer->setSingleShot(true);
timer->start(timestate[0]);
case 2000:
send[2]=LightState(1);
connect(timerr, SIGNAL(timeout()), this, SLOT(senddata()));
timerr->setSingleShot(true);
timerr->start(timestate[1]);
case 3000:
send[2]=LightState(2);
connect(timerrr, SIGNAL(timeout()), this, SLOT(senddata()));
timerrr->setSingleShot(true);
timerrr->start(timestate[2]);
}
} -
there really needs to be a "required reading" section for Qt, before people ask questions. As we see again, trying to use sequential/procedural programming instead of the event driven model.
staggering timer events only needs a single timer implementation. in the callback from Qtimer(1000ms)::TimerExpired() execute a switch sstatement based on a static var that is incremented every time the timer expires. in the "case" segments put your light (on/off) logic.
-
@JonB Dear JohB.
I added the qDebug() << "senddata()"; to the senddata. Then i run
It outputs 3 times and each time with the last packet. It sends the last packet 3 times.
I tested it with switch/case but it still sends the last packet .
for (int i = 0; i < 4; i++)
{
switch(timestate[i]) {
case 1000:
send[2]=LightState(0);
connect(timer, SIGNAL(timeout()), this, SLOT(senddata()));
timer->setSingleShot(true);
timer->start(timestate[0]);
case 2000:
send[2]=LightState(1);
connect(timerr, SIGNAL(timeout()), this, SLOT(senddata()));
timerr->setSingleShot(true);
timerr->start(timestate[1]);
case 3000:
send[2]=LightState(2);
connect(timerrr, SIGNAL(timeout()), this, SLOT(senddata()));
timerrr->setSingleShot(true);
timerrr->start(timestate[2]);
}
}@n_moosavi
So you know yoursenddata()slot is being hit 3 times, which was the objective of the exercise. What you do insenddata()is up to you, you seem towrite(send);. And that will be in whatever state you left it after yourfor ... switchloop, which perhaps meanssend[2]=LightState(2);, and that is what you are complaining about.Since the loop runs when you are setting the timers up, not when the timers expire, if you change
send[]there that will affect when all the timers expire, which is perhaps not what you want. So you need to alter code in that light. -
there really needs to be a "required reading" section for Qt, before people ask questions. As we see again, trying to use sequential/procedural programming instead of the event driven model.
staggering timer events only needs a single timer implementation. in the callback from Qtimer(1000ms)::TimerExpired() execute a switch sstatement based on a static var that is incremented every time the timer expires. in the "case" segments put your light (on/off) logic.
@Kent-Dorfman thanks for your help, I'm new to QT, and I know that I should work harder.
-
QTimer as a counter using dynamic property:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { auto* timer=new QTimer; timer->setProperty("count",5); connect(timer,&QTimer::timeout,this, &MainWindow::timeout); timer->start(1000); } void MainWindow::timeout() { QTimer* timer=qobject_cast<QTimer*>(sender()); if(timer==nullptr) return; // error wrong sender int count=timer->property("count").toInt()-1; timer->setProperty("count",count); qDebug()<<__FUNCTION__<<count; // call sendData() here if(count<=0) { timer->stop(); delete timer; } } -
@n_moosavi
So you know yoursenddata()slot is being hit 3 times, which was the objective of the exercise. What you do insenddata()is up to you, you seem towrite(send);. And that will be in whatever state you left it after yourfor ... switchloop, which perhaps meanssend[2]=LightState(2);, and that is what you are complaining about.Since the loop runs when you are setting the timers up, not when the timers expire, if you change
send[]there that will affect when all the timers expire, which is perhaps not what you want. So you need to alter code in that light.