How to create some Timers at run time and handle them?
-
Hi,
In my application I want to create some timers at run time and handle their events separately and also reset them when needed.
I tried but couldn't find a way to do this.
when I use startTimer() function to creates some timers, I can't find how to reset specific timer!
when use QTimer in the event handler slot can't determine which timer time outed!
Thank you in advance. -
@J-Hilk I test this code, It only passes the last timer ID.
if (!List.contains(str)) { // Start timer timer = new QTimer(this); timer->setInterval(200); timer->start(); connect(timer, &QTimer::timeout, this, [=]()->void{integrityTimersEvent(timer->timerId());}); // timersList.append(timer); timersIDList.append(timer->timerId()); }
void FrameProcessor::integrityTimersEvent(int timerID) { qDebug() << "integrityTimersEvent => Timer ID:" << timerID; }
Am I doing it right way?
@Jamshid
actually thistimer = new QTimer(this); timer->setInterval(200); timer->start(); connect(timer, &QTimer::timeout, this, [=]()->void{integrityTimersEvent(timer->timerId());});
is referencing the member variable
try the following:
QTimer *t = new QTimer(this); t->setInterval(200); t->start(); connect(t, &QTimer::timeout, this, [=]()->void{integrityTimersEvent(t->timerId());}); timer = t;
-
Hi
What about using lambdas and capture the timer?
Then you don't need to keep track of anything.QObject::connect(timer, &QTimer::timeout, [timer](){ timer->stop(); }); QObject::connect(timerOther, &QTimer::timeout, [timerOther](){ timerOther->stop(); });
-
Hi,
In my application I want to create some timers at run time and handle their events separately and also reset them when needed.
I tried but couldn't find a way to do this.
when I use startTimer() function to creates some timers, I can't find how to reset specific timer!
when use QTimer in the event handler slot can't determine which timer time outed!
Thank you in advance.@Jamshid Apart form QTimer (you can use it as a member variable, as you know) QObject - and every class derived from - has built in one. How to use:
When you run startTimer() method returns an int value that is the id of given timer. If you override timerEvent() method you'll see that a parameter is of QTimerEvent type. In that event you have a method called timerID which in turn is the ID of the timer that expired.
So, start as many timers as you need, store the IDs, then in timerEvent() simply check against the table to find out which one called the event.Other solution is have a farm of QTimer variables and connect their timeout() signals to specific slots.
Hope this helps.
-
@Jamshid Apart form QTimer (you can use it as a member variable, as you know) QObject - and every class derived from - has built in one. How to use:
When you run startTimer() method returns an int value that is the id of given timer. If you override timerEvent() method you'll see that a parameter is of QTimerEvent type. In that event you have a method called timerID which in turn is the ID of the timer that expired.
So, start as many timers as you need, store the IDs, then in timerEvent() simply check against the table to find out which one called the event.Other solution is have a farm of QTimer variables and connect their timeout() signals to specific slots.
Hope this helps.
@artwaw thanks,
startTimer() does not have reset function and when I create some timers with this method can't have access to them later for restarting. They just provide their ID and I did timerEvent() override.
In my application It's not determined how many timers needed, maybe 2 or maybe 100.
So using QTimer with specific slots won't work. -
@artwaw thanks,
startTimer() does not have reset function and when I create some timers with this method can't have access to them later for restarting. They just provide their ID and I did timerEvent() override.
In my application It's not determined how many timers needed, maybe 2 or maybe 100.
So using QTimer with specific slots won't work.@Jamshid Unless someone more experienced have other way I'd go somewhere along that way:
- derive from QTimer and include just one field: id, lets assume it is qint32 or something and name teh class here QTimer2;
- create QHash<int,QTimer2*>
And store the pointers and position that is equal to field id in QTimer2. This way you'll be able to examine which instance called and connect signals/slots.
Mind you, I don't find this solution very elegant. This is only rough idea and there might be better one.
-
Hi
What about using lambdas and capture the timer?
Then you don't need to keep track of anything.QObject::connect(timer, &QTimer::timeout, [timer](){ timer->stop(); }); QObject::connect(timerOther, &QTimer::timeout, [timerOther](){ timerOther->stop(); });
-
@Jamshid said in How to create some Timers at run time and handle them?:
So using QTimer with specific slots won't work.
There is always QObject::sender() where you can see where the signal is coming from. Apart from this why not storing all created timers in a QVector/QHash/whatever so you can access them later on?
-
@Jamshid Unless someone more experienced have other way I'd go somewhere along that way:
- derive from QTimer and include just one field: id, lets assume it is qint32 or something and name teh class here QTimer2;
- create QHash<int,QTimer2*>
And store the pointers and position that is equal to field id in QTimer2. This way you'll be able to examine which instance called and connect signals/slots.
Mind you, I don't find this solution very elegant. This is only rough idea and there might be better one.
-
@Jamshid said in How to create some Timers at run time and handle them?:
So using QTimer with specific slots won't work.
There is always QObject::sender() where you can see where the signal is coming from. Apart from this why not storing all created timers in a QVector/QHash/whatever so you can access them later on?
@Christian-Ehrlicher I'm trying sender(), I can store created timers in a vector and connect all created timers' timeout signal to one slot, my problem is this how to determine in that slot which timer timed out. I think QObject::sender() will help. let me try it.
-
@Christian-Ehrlicher I'm trying sender(), I can store created timers in a vector and connect all created timers' timeout signal to one slot, my problem is this how to determine in that slot which timer timed out. I think QObject::sender() will help. let me try it.
@Jamshid I would actually suggest to use a lambda over the sender() approach
for(int i(0); i <10; i++){ QTimer *t = new QTimer(this); connect(t, &QTimer::timeout, this, [=]()->void{timerSlot(i);}); m_timers.append(t); } ... public slots: void timerSlot(int timeId);
-
@Christian-Ehrlicher I'm trying sender(), I can store created timers in a vector and connect all created timers' timeout signal to one slot, my problem is this how to determine in that slot which timer timed out. I think QObject::sender() will help. let me try it.
@Jamshid
For a slot functionsender
should give you which timer. My understanding (untested!) is that if you use a lambda you do not get asender
. But then @J-Hilk is, I think, offering a lambda which passes thetimerId
as a parameter for you. Both sound like they would work. -
@Jamshid
For a slot functionsender
should give you which timer. My understanding (untested!) is that if you use a lambda you do not get asender
. But then @J-Hilk is, I think, offering a lambda which passes thetimerId
as a parameter for you. Both sound like they would work.@JonB well, yes, we originally talked about identifying the timer that called the slot, what better way than an int ? 😉
Well, If one is more interested in the Timer Object....
for(int i(0); i <10; i++){ QTimer *t = new QTimer(this); connect(t, &QTimer::timeout, this, [=]()->void{timerSlot(t);}); m_timers.append(t); } ... public slots: void timerSlot(QTimer *timer);
-
@Jamshid I would actually suggest to use a lambda over the sender() approach
for(int i(0); i <10; i++){ QTimer *t = new QTimer(this); connect(t, &QTimer::timeout, this, [=]()->void{timerSlot(i);}); m_timers.append(t); } ... public slots: void timerSlot(int timeId);
@J-Hilk I test this code, It only passes the last timer ID.
if (!List.contains(str)) { // Start timer timer = new QTimer(this); timer->setInterval(200); timer->start(); connect(timer, &QTimer::timeout, this, [=]()->void{integrityTimersEvent(timer->timerId());}); // timersList.append(timer); timersIDList.append(timer->timerId()); }
void FrameProcessor::integrityTimersEvent(int timerID) { qDebug() << "integrityTimersEvent => Timer ID:" << timerID; }
Am I doing it right way?
-
@J-Hilk I test this code, It only passes the last timer ID.
if (!List.contains(str)) { // Start timer timer = new QTimer(this); timer->setInterval(200); timer->start(); connect(timer, &QTimer::timeout, this, [=]()->void{integrityTimersEvent(timer->timerId());}); // timersList.append(timer); timersIDList.append(timer->timerId()); }
void FrameProcessor::integrityTimersEvent(int timerID) { qDebug() << "integrityTimersEvent => Timer ID:" << timerID; }
Am I doing it right way?
@Jamshid , @J-Hilk
It only passes the last timer ID.
This is just the kind of behaviour I found when playing with lambdas (which is why I don't much like them, let's not go there)! To get it right, I believe, you must pass the
timer->timerID()
, or the wholetimer
, as a parameter to the lambda. Not sure of the C++ (I'm Python) syntax, but I think it must go inside the()
you have...EDIT Oh well, since @J-Hilk shows it works below, I must be mistaken, sorry.... I had this kind of problem with Python lambdas, they must not directly access a changing value in the caller in their body code, instead the caller must pass that as a parameter....
-
@J-Hilk I test this code, It only passes the last timer ID.
if (!List.contains(str)) { // Start timer timer = new QTimer(this); timer->setInterval(200); timer->start(); connect(timer, &QTimer::timeout, this, [=]()->void{integrityTimersEvent(timer->timerId());}); // timersList.append(timer); timersIDList.append(timer->timerId()); }
void FrameProcessor::integrityTimersEvent(int timerID) { qDebug() << "integrityTimersEvent => Timer ID:" << timerID; }
Am I doing it right way?
@Jamshid
should work fine,take a look at the example I made:
int MainWindow::count = 0; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { for(int i(0); i <10; i++){ QTimer *t = new QTimer(this); connect(t, &QTimer::timeout, this, [=]()->void{timerSlot(t->timerId());}); m_timers.append(t); t->start(100); } } void MainWindow::timerSlot(int timerId) { qDebug() << timerId; qDebug() << Q_FUNC_INFO << count++; }
which results in the correct call of:
1 void MainWindow::timerSlot(int) 0 2 void MainWindow::timerSlot(int) 1 3 void MainWindow::timerSlot(int) 2 4 void MainWindow::timerSlot(int) 3 5 void MainWindow::timerSlot(int) 4 6 void MainWindow::timerSlot(int) 5 7 void MainWindow::timerSlot(int) 6 8 void MainWindow::timerSlot(int) 7 9 void MainWindow::timerSlot(int) 8 10 void MainWindow::timerSlot(int) 9 1 void MainWindow::timerSlot(int) 10 2 void MainWindow::timerSlot(int) 11 3 void MainWindow::timerSlot(int) 12 4 void MainWindow::timerSlot(int) 13 5 void MainWindow::timerSlot(int) 14 6 void MainWindow::timerSlot(int) 15 7 void MainWindow::timerSlot(int) 16 8 void MainWindow::timerSlot(int) 17 9 void MainWindow::timerSlot(int) 18 10 void MainWindow::timerSlot(int) 19 1 void MainWindow::timerSlot(int) 20 2 void MainWindow::timerSlot(int) 21 3 void MainWindow::timerSlot(int) 22 4 void MainWindow::timerSlot(int) 23 5 void MainWindow::timerSlot(int) 24 6 void MainWindow::timerSlot(int) 25 7 void MainWindow::timerSlot(int) 26 8 void MainWindow::timerSlot(int) 27 9 void MainWindow::timerSlot(int) 28 10 void MainWindow::timerSlot(int) 29 1 void MainWindow::timerSlot(int) 30 2 void MainWindow::timerSlot(int) 31 3 void MainWindow::timerSlot(int) 32 4 void MainWindow::timerSlot(int) 33 5 void MainWindow::timerSlot(int) 34 6 void MainWindow::timerSlot(int) 35 7 void MainWindow::timerSlot(int) 36 8 void MainWindow::timerSlot(int) 37 9 void MainWindow::timerSlot(int) 38 10 void MainWindow::timerSlot(int) 39 1 void MainWindow::timerSlot(int) 40 2 void MainWindow::timerSlot(int) 41 3 void MainWindow::timerSlot(int) 42 4 void MainWindow::timerSlot(int) 43 5 void MainWindow::timerSlot(int) 44 6 void MainWindow::timerSlot(int) 45 7 void MainWindow::timerSlot(int) 46 8 void MainWindow::timerSlot(int) 47 9 void MainWindow::timerSlot(int) 48 10 void MainWindow::timerSlot(int) 49 1 void MainWindow::timerSlot(int) 50
edit: @JonB
the [=] is a "capture everything by copy" indicator. So no explicit capture of the id should be required -
@J-Hilk I test this code, It only passes the last timer ID.
if (!List.contains(str)) { // Start timer timer = new QTimer(this); timer->setInterval(200); timer->start(); connect(timer, &QTimer::timeout, this, [=]()->void{integrityTimersEvent(timer->timerId());}); // timersList.append(timer); timersIDList.append(timer->timerId()); }
void FrameProcessor::integrityTimersEvent(int timerID) { qDebug() << "integrityTimersEvent => Timer ID:" << timerID; }
Am I doing it right way?
@Jamshid said in How to create some Timers at run time and handle them?:
Am I doing it right way?
I would guess timer is a member variable, then yes you're doing it wrong. You copy the whole context ( [=]) and therefore the access inside the lambda is 'this->timer'
-
@J-Hilk I test this code, It only passes the last timer ID.
if (!List.contains(str)) { // Start timer timer = new QTimer(this); timer->setInterval(200); timer->start(); connect(timer, &QTimer::timeout, this, [=]()->void{integrityTimersEvent(timer->timerId());}); // timersList.append(timer); timersIDList.append(timer->timerId()); }
void FrameProcessor::integrityTimersEvent(int timerID) { qDebug() << "integrityTimersEvent => Timer ID:" << timerID; }
Am I doing it right way?
@Jamshid
actually thistimer = new QTimer(this); timer->setInterval(200); timer->start(); connect(timer, &QTimer::timeout, this, [=]()->void{integrityTimersEvent(timer->timerId());});
is referencing the member variable
try the following:
QTimer *t = new QTimer(this); t->setInterval(200); t->start(); connect(t, &QTimer::timeout, this, [=]()->void{integrityTimersEvent(t->timerId());}); timer = t;
-
@Jamshid
actually thistimer = new QTimer(this); timer->setInterval(200); timer->start(); connect(timer, &QTimer::timeout, this, [=]()->void{integrityTimersEvent(timer->timerId());});
is referencing the member variable
try the following:
QTimer *t = new QTimer(this); t->setInterval(200); t->start(); connect(t, &QTimer::timeout, this, [=]()->void{integrityTimersEvent(t->timerId());}); timer = t;