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
timer
instance, and youstart(timestate[i]);
it 4 times with a differenttimestate[i]
each time. This will end up with just the onetimer
started on the finaltimestate[i]
value.It is hard to know what you are wanting to achieve here. Do you want 4 distinct
QTimer
s for each of thetimestate[i]
values? Does each timer want to count its time (delay) from when the first one was started, or does eachtimestate
value want to count/delay from when the previous one timed out? -
@n_moosavi
Hello and welcome.You have a single
timer
instance, and youstart(timestate[i]);
it 4 times with a differenttimestate[i]
each time. This will end up with just the onetimer
started on the finaltimestate[i]
value.It is hard to know what you are wanting to achieve here. Do you want 4 distinct
QTimer
s for each of thetimestate[i]
values? Does each timer want to count its time (delay) from when the first one was started, or does eachtimestate
value 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 yourtimestate
array. -
Create one
QTimer
(singleshot). Keep a member variable to count throughtimestate
so 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 intimestate
for this time's value and the previous one, re-load the singleQTimer
instance with that (all would be1000
given 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 yourtimestate
array. -
Create one
QTimer
(singleshot). Keep a member variable to count throughtimestate
so 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 intimestate
for this time's value and the previous one, re-load the singleQTimer
instance with that (all would be1000
given 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 ... switch
loop, 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 ... switch
loop, 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.