Using sleep_for() in Qt application - c++

In my application I want to display some image with this code
myImage = scene->addPixmap(image);
myImage->setOffset(x, y);
Then I want to sleep for some seconds:
std::this_thread::sleep_for(std::chrono::seconds(2));
and then display another image. But this code waits for 2 seconds at first and then displays both images at once. How can I make the program wait between displaying those two images?

Use QTimer::singleShot() and connect it to a slot that updates the picture:
class MyObject : public AQObjectInheritingClass
{
Q_OBJECT
...
public Q_SLOTS:
void changeImage()
{
//change image here
}
And in instead of sleep_for():
QTimer::singleShot(2000, &instanceOfMyObject, SLOT("changeImage()");
Two seconds later, changeImage() will be invoked.

You cannot sleep in event based application (GUI applications are event-based). Event based applications have main loop, that has to be running to process events, and update its state. Calling sleep_for stops that main loop, so your app doesn't process events so it doesn't react to input and doesn't repaint itself. That's why all drawing if deferred fot two seconds then flushed at once.
As an alternative, you should use timers, such as QTimer

there is Qt-specific non-blocking way to pause thread with QEventLoop:
QEventLoop loop;
QTimer::singleShot(1000,&loop,SLOT(quit()));
loop.exec();
While loop is being executed, all other events for this thread are processed.

Related

How to properly using infinite loop in Qt GUI?

I am new to and learning the Qt GUI framework.
I have an ultrasonic sensor wired up to the Raspberry Pi, to measure water level. If I were coding in C, I would have used a while(1) loop to constantly read the sensor input. But when I put while(1) inside MainWindow.cpp, the window cannot be displayed. However, using qDebug() I can still print out the sensor value, which means my while(1) still running but the main window won't appear. I found out in this answer that because of while(1),
MainWindow ctor never returns, so w.show() is never called and a.exec() (main message loop) is never executed.
To solve this, I use QTimer instead of a loop: connect the timeout() SIGNAL to a SLOT which is a function to read the sensor value one-time:
waterLevelTimer = new QTimer(this);
connect(waterLevelTimer, SIGNAL(timeout()), this, SLOT(getWaterLevel()));
waterLevelTimer->start(100); // "loop" once every 100 millisecond
With this method, I can read the sensor value with the fastest interval is 1 millisecond and the GUI still displayed fine.
But should I use QTimer to mimic a while(1) loop? Is there a better way to have an infinite loop to read GPIOs while still being able to use GUI for other work?
The main thread where the GUI of Qt runs never should be blocked by long-lasting operations like an infinite while-loop, because otherwise you would block the event system and nothing will work anymore.
Instead you usually create a worker thread in parallel (see QThread) where you do your loop in the run function of the thread. Maybe also use such timer as you suggest, which works if the executed code is faster than the timer duration.
QThread *thread = QThread::create([]{
while(1)
checkSomething();
});
thread->start();

Why does qt show () not have priority?

I'm using Qt for an application.
I would like to display a window then put a timer and display a second window.
But currently the timer is done then the 2 windows open at the same time
this->firstWindow->show();
QTime dieTime = QTime::currentTime().addSecs(10);
while (QTime::currentTime() < dieTime);
this->secondWindow->show();
I tried a lot of solutions, like putting the show() of the firstwindow directly into the constructor but nothing works.
You are using a blocking while loop to wait for the time to elapse, so the GUI thread cannot update the user interface. You could use QTimer for a non-blocking wait or refresh the GUI by adding qApp->processEvents(QEventLoop::AllEvents, 100); into the while loop.
I would prefer QTimer, because then you are not creating your own event loop. For example:
QTimer::singleShot(10000, this->secondWindow, SLOT(show()));

Multithreading advice

I am developing an application, the main goal is to grab images from a frame grabber, do some processing and then show images on a GUI.
The frame grabber is connected to the PCIe. And I'm using the frame grabber SDK.
The image stream is pretty slow 10 to 100 images/s
I am here to have some advice about my code and how to optimize it.
First, there is my run() function from a class inherited from Qthread
I grab an image and put it on a buffer queuecv:: Mat>.
void ImageIn::run(){
_cam->allocMemory();
_cam->startAquisition();
_runningThread = true;
while(_runningThread)
{
Mat image(_cam.getSizeX(), _cam.getSizeY(), CV_16U, _cam->getImageDMA0());
_ctrl->getMutexIn()->lock(); // Lock BufferIn
_ctrl->getBufferIn()->push(image); // store Image in BufferIn
_ctrl->getMutexIn()->unlock(); // Unlock bufferIn
}
}
Images are stored in a buffer and then the processing thread do some work...
void ImageProcessing::run(){
while(_runningThread){
if (_ctrl->getMutexIn()->tryLock()){
while(!_ctrl->getBufferIn()->empty()){
_ctrl->getBufferIn()->front().convertTo(tempConvert, CV_32F);
_bufferLocalIn.push(tempConvert);
_ctrl->getBufferIn()->pop();
}
_ctrl->getMutexIn()->unlock();
}
// Do some processing and put image and a buffer for GUI
}
}
So, I have some questions:
- The thread 1 gets images thanks to a blocking function, so the CPU consumption is low, but the thread 2 run continuously and consumes a lot of CPU reassess what can I do for fixing that?
- is it the right way to code that?
So i tried that :
QThread* thread = new QThread;
ImageWriter* worker = new ImageWriter();
worker->moveToThread(thread);
QTimer* timer = new QTimer();
int msec = 100;
timer->setInterval(msec);
QObject::connect(thread, SIGNAL(started()), worker, SLOT(process()));
QObject::connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
QObject::connect(timer, SIGNAL(timeout()), thread, SLOT(start()));
timer->start();
is it ok ?
As Qt is an event driven framework, each thread has an event queue which receives events and sends them to various objects to receive them.
If any section of code in a thread has essentially a while(1) loop, then event propagation cannot occur and this is what you're doing in both threads with
while(_runningThread)
Starving the event processing in an infinite loop is the cause of excessive CPU consumption.
It is possible to use to get Qt to process events with a call to QApplication::processEvents within the infinite loops, but this is not ideal.
A better method would be to time-slice the processing with QTimer and allow the event propagation to occur naturally. This would require deciding how long processing could occur, before saving the processing state and then returning back to the event loop. A tick of the timer would call your processing function which can then restore state and resume.
This method will be easier if you create a processing class derived from QObject which you move to a QThread, rather than inheriting directly from QThread itself. There's a great article on How to Really Truly Use QThread which can be used as a template on how to do this.
Finally, consider that you can have more than one QThread, as well as more than one QObject running on a QThread. As a general rule, you will not benefit if the number of threads exceeds the number of processor cores available.
If you know the target machine is a quad core, you can create 3 extra QThreads (4 in total, including main), create multiple processing objects and move them to different threads to provide optimal processing.

QT GUI Horizontal Slider setValue with QElapsedTimer

I have a GUI Button that calls a shell script to start recording a video. In addition I want a slider to show progress of recording (maximum recording time is 30 seconds). I build the following function:
coid MainWindow::on_recordStart_clicked()
{
QElapsedTimer timer;
QProcess *Prozess = new QProcess();
Prozess->start("record.sh");
timer.start();
for(;;)
{
ui->timelineLabel->setText(QString::number(timer.elapsed())); //label
ui->timeLine->setValue(timer.elapsed()); //slider
if (timer.hasExpired(30000)) break;
}
It only updates the Slider and Label after the break. Anyone knows why?
Your main (UI) thread is busy iterating through your for loop and won't be able to handle the events to update your label.
There is one quick and dirty solution (not tested), add the following line after setValue:
QCoreApplication::processEvents();
The nicer solution would to move the process handling to a separate thread and notify the main thread about the progress via a signal/slot.

Qt How to update main windows from running thread , the right way

I have simple application that in the main view I have QListview . my flow going like this I need to know if it right
1.App starts and start single thread , also see signal/slot connect between the thread object and the main app
2.Thread gets data from remote server as xml format its and sets the data into object container (class that represent the data )
3.when the data is ready in the object it trigger SIGNAL back to the main app (the signal/slot from section 1)
4.The SIGNAL invoking update function that sets the formatted data into the QListView via its model (QAbstractListModel)
The problem is when stage 4 is happening I see some frize in the application for 2-3 seconds that makes me wonder what is wrong here .
UPDATE:
after profiling the app with sleepy
it looks like the delay in the app im not sure but is shows in the Exclusive column
very high number 322.35s.
in my Thread that calls the http request inside the run method i have this code that couse the thread to pause.
void RequestThread::run()
{
m_RequestThreadTimer = new QTimer();
connect(m_RequestThreadTimer, SIGNAL(timeout()),
this,SLOT(fire(),Qt::DirectConnection));
QVariant val(GetValFromConfig());
int interval = val.toInt();
m_RequestThreadTimer->setInterval(interval);
m_RequestThreadTimer->start();
QThread::exec();
}
but now is the question how to improve it ?
I suspect that since you create the timer in the QThread::run() method the slot the timer connects to is being called in the context of the main thread.
You don't need to subclass QThread to run code in its own thread.
Just subclass a QObject, add the functionality you want, create a QThread instance, start it and use the QObject::moveToThread() method to set the QObject's thread affinity to the new thread.
worker = new WorkerClass;
connect(worker,SIGNAL(response(QString)),this,SLOT(response(QString)));
QThread *t = new QThread;
t->start();
worker->moveToThread(t);
//Start it either like this or by emitting a signal connected to the startWorking slot
QMetaObject::invokeMethod(worker,"startWorking",Qt::QueuedConnection);
I suggest you to use the QEventloop in the case of the thread.
Start the event loop in the main
//start the function to get data from remote server
GetData::getInstance()->StratReading();
QEventLoop loop; //loop to continue the reading.
loop.connect(GetData::getInstance(),SIGNAL(ReadingFinished()),SLOT(quit()));
loop.exec();
GetData::StratReading()
{
//sets the data into object container
//the data is ready in the object it trigger SIGNAL to main function to update to Ui
emit ReadingFinished(); //this will quit the loop
}