Is it possible to call a function periodically in C++ with Qt function ?
And how to stop the timed function after it is set to be called periodically ?
If you are using qt, you can you QTimer which by default creates a repetitive timer.
There is an example in the documentation (shown below) and an example (Analog Clock).
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
timer->start(1000);
One possibility would be to use a QTimer timeout signal and a QObject slot. Connect the two and start() the timer.
http://qt-project.org/doc/qt-4.8/qtimer.html#timeout
To stop the timer, call stop().
As people have said in answers before me, you can use the timeout() signal to trigger a function to run.
If you want to stop the timer at some point, you can connect to the stop() slot, or call it directly yourself.
You can use the QTimer class.
Just declare a QTimer with the desired time interval, wrap your function in a QObject as a slot, and connect the QTimer's timeout() signal to the slot you just declared.
Then, when the condition for stopping calling the function is met, just call QTimer::stop().
Make a function that uses timer functionallity or a while loop that just waits for 100 ms and when your function meets the requirement just break. You could quite easy found a solution on this one if you just made a search among all the other questions that has been posted here.
Related
I am currently starting on QTCreator. I have been asked to use QTimers in a particular context which is this:
We have an open window,
One or more QTimers are triggered and make things appear on the screen every x msec.
When we press "Escape" the window should close and everything should be reset to 0.
But here is the problem, the timers are defined in a static way:
QTimer::singleShot(500, this, SLOT(foo());
When I call this->close() (which closes my window), the timers do not stop and continue. I tried several solutions: browse all the QTimers contained in my object, obviously there are none since they are defined in static. Instead of declaring them in static I've tried to create each time a new QTimer object like that:
QTimer *timer= new QTimer(this);
timer->setSingleShot(true);
timer->setInterval(2000);
timer->setParent(this);
timer->start();
And then call timer->stop() later, but I think it's very brutal when you have multiple Timers in the same code.
Is there a way to stop the timers when this->close is called, knowing that the timers are defined as a static one ?
Assuming you are using,
QWindow *qw = new QWindow();
QTimer *timer= new QTimer();
To solve the issue you need to connect destroyed() signal of QWindow to timer's slot stop()
So as soon as window is destroyed all registered timers will be stopped without explicit stop call. make sure you connect all timer instances. Code snippet as following,
QObject::connect(&qw, SIGNAL(destroyed()), timer, SLOT(stop()))
QObject::connect(&qw, SIGNAL(destroyed()), timer2, SLOT(stop()))
QObject::connect(&qw, SIGNAL(destroyed()), timer3, SLOT(stop()))
PS:
QTimer *timer= new QTimer(this); // here you are setting parent as 'this' already
timer->setSingleShot(true);
timer->setInterval(2000);
timer->setParent(this); // remove this, no need to set parent again.
timer->start();
I'm trying to make a program in Qt. I will not send all, but the fragment with which I have a problem. The point is, I have to interrupt a function that has a Timer in it, but I don't know how to interrupt it while it's waiting before timer. 😕 Please reply!
void MainWindow::Test(){
TestWrite(); //TestWrite is a function where I write my answer
QTimer::singleShot(5000, this, &MainWindow::TestCheck); //TestCheck is a function where the answer is checked
}
void MainWindow::on_Test_clicked()
{
Test();
timer = new QTimer(this); //Creates a timer and calls the Test function every 7 seconds
timer->connect(timer, &QTimer::timeout, this, &MainWindow::Test);
timer->start(7000);
}
........
........
void MainWindow::on_Back_clicked()
{
timer->stop(); //I am trying to make the "Back" button interrupt the Test, TestWrite and TestCheck functions. Now, if you quickly click "Back" and "Test", the effect is as if you did not click the "Back" button
}
Timers in Qt that you start with the static QTimer functions (like you do in MainWindow::Test) cannot be stopped at all, because there's no timer object exposed to you that you could use to stop() (or otherwise manipulate) the timer. Such timers will expire in any case, and they will emit their signal in any case. You need to decide in your slot whether you're still interested in the signal.
When you create an explicit timer object (as you do in on_test_clicked(), you can only stop() it, or re-start() it with a minimum expiry time (0) to have it expire "immediately".
If you don't want to have a timer expire that you already started, simply stop() it.
The way you stated your question shows a possible mis-understanding of how timers work in Qt. Nothing is "waiting" for a timer, but rather an expired timer sends a signal to a slot. "Waiting" in Qt would freeze your user interface.
I'm asking in a case where there is a lot of qt events queued in event engine. Does QTimer emit timeout() signal through event and will with queuedConnection to a slot create another event?
The slots connected with Qt::DirectConnection will be called immediately when the QTimer::timeout signal is emitted by QTimer. If you use a queued connection, it will schedule an event to call the slot, which will be processed by the event loop. QTimer uses timerEvent to emit the timeout signal.
No it is not queued connection by default unless it is running in a different thread. Therefore it is DirectConnection.
I would say that, in general, if you want to guarantee a sequential order of events you are better of using Qt::QueuedConnection with things like timers even when in the same thread so that the event goes onto the queue and is not just acted upon immidiatley - since this behaviour is some-what more like an "interrupt".
However if you really want the timer timeout() to be acted on immediately then use Qt::DirectConnection - I feel that you need to be more careful with this connection type in general (with things like timers which can trigger in the middle of other normal code).
Edit
By "normal code" I mean...well, see comments below:
When a QTimer times out, every Signal-Slot connection, which joins signal of this QTimer with an slot, fires this slot exactly one time.
I'm using a library where I need to call a trigger function that starts some processing (starts a thread that does the job) and returns immediatly. Then when the processing is finished a signal is emitted.
This needs to be done periodically based on different parameters. Since other calls to the trigger function must not be done while processing I would need to queue them in some way. I thought about using a QEventLoop ("loop") but without luck so far.
Please look at this piece of code:
test::test()
{
connect(&timer, SIGNAL(timeout()), this, SLOT(timerSlot()));
connect(&timer2, SIGNAL(timeout()), this, SLOT(timer2Slot()));
connect(&library, SIGNAL(processingFinished()), &loop, SLOT(quit()));
timer.setInterval(2000);
timer.start();
timer2.setInterval(4000);
timer2.start();
}
void test::timerSlot()
{
loop.exec();
startProcessing(some_parameters);
}
void test::timer2Slot()
{
loop.exec();
startProcessing(some_other_parameters);
}
The issue is that when loop.exec() is called while processing I get the message:
QEventLoop::exec: instance xxxxxx has already called exec()
What would be the right way to do what I intend?
Thanks in advance.
One simple solution is to introduce a member variable, for example, bool m_isProcessing, start processing only if m_isProcess == false, then set it to true when you start processing and reset it to false when processing is complete. Since the slots for your test QObject execute on the GUI/main thread, you don't need to worry about synchronization between timer slots and the slot that will execute when processing is finished.
If you want to keep track of events that occur during processing, you can use the same method: introduce a member variable to the test class to track the information you need.
It seems that you are looking for Qt::QueuedConnection.
Qt::QueuedConnection 2 The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.
Therefore, you could write something like this:
connect(&timer, SIGNAL(timeout()), SLOT(timerSlot()), Qt::QueuedConnection);
connect(&timer2, SIGNAL(timeout()), SLOT(timer2Slot()), Qt::QueuedConnection);
For details, you could look into the well-known mandelbrot example how this is done in there, although it is using worker threads:
Mandelbrot Example
Does QT provide any functions to control a progress bar's speed? For example, if I want it to increase by 1% every 1 second, is there any QT way to do it instead of using a loop and sleeping for 1 second between each value change?
You can use QTimeLine for this. The detailed description in the documentation gives an example of exactly what you want.
Use a QTimer.
Connect the signal timeout() to a slot that increases the value in the QProgressBar.
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
timer->start(1000);
In this cas, update() will be call each second.
If you're using Qt 4.6 you can also use QPropertyAnimation