How can I pause an action in real time (Qt5)? - c++

I have a function that reads some commands and does things related to that commands. The problem is that I want to pause the program after each command. This is my code:
void MainWindow::moveDown(){
QPoint l = ui->label->pos();
int x = l.rx();
int y = l.ry();
if(y+50 <= 630){
QPixmap pix(":/resources/img/Penguin.png");
int w = ui->label->width();
int h = ui->label->height();
ui->label->setPixmap(pix.scaled(w,h,Qt::KeepAspectRatio));
y = y+50;
ui->label->setGeometry(x, y, 50, 50);
//sleep(1);
}
}
As you can see, I have tried the sleep() function, but it pauses the program before the label starts moving. What else should I try?

I implemented this function many years ago that I've been using since. It keeps the event loop going so that the UI doesn't freeze during the sleep. It does this by executing a local event loop for the requested amount of milliseconds. It also aborts the loop if the application wants to quit:
/*
* Sleep for 'ms' milliseconds without freezing the UI.
*/
void sleepLoop(const long ms)
{
QEventLoop idle_loop;
QTimer timer;
timer.setSingleShot(true);
QObject::connect(&timer, &QTimer::timeout, &idle_loop, &QEventLoop::quit);
QObject::connect(qApp, &QCoreApplication::aboutToQuit, &idle_loop, &QEventLoop::quit);
timer.start(ms);
idle_loop.exec();
}

Related

GUI app frozen while process and generate a file

I have a QT GUI application in c++ that aims to process and generates binary files.
The App works fine but it looks like it's frozen when it enters the while loop of processing and writing in the file.
I solve this by coping qApp->processEvents(); into the while loop. but the problem is that it takes much more time for generating a file:
without qApp->processEvents(); in the loop => it takes 4second
with qApp->processEvents(); in the loop => it takes 50 second for exact the same file
for (unsigned long int k=0; k<DATASIZE ; k++){
qApp->processEvents();
/* Some process*/
DataToFile.push_back(Process_Function(DATA));
}
/*Generating file*/
myFile.write((char *)&DataToFile[0], DataToFile.size()*sizeof (float));
DATA SIZE around a couple of millions
Process_Function: take specific data, calculate the value and return it back.
Questions:
1- Is there a way to process the data, generate files without being frozen and without the huge delay of the qApp->processEvents();
2- Is it possible to run qApp->processEvents(); in another thread? / OR is there another way to do it?
First, create an object that encapsulates your work:
class Generator : public QObject {
Q_OBJECT
signals:
void progress(float);
void done();
slots:
void doWork() {
QVector<float> DataToFile;
for (unsigned long int k=0; k<DATASIZE ; k++){
/* Some process*/
DataToFile.push_back(Process_Function(DATA));
if (k % 100 == 0) { // Inform the UI thread every 100 datapoints
emit progress(k/DATASIZE);
}
}
myFile.write((char *)&DataToFile[0], DataToFile.size()*sizeof (float));
emit done();
}
};
Then create a new thread and have the object do its work there:
QThread *t = new QThread(this);
Generator *g = new Generator;
g->moveToThread(t);
QObject::connect(t, &QThread::started, g, &Generator::doWork);
QObject::connect(g, &Generator::done, t, &QThread::quit);
QObject::connect(t, &QThread::finished, g, &QObject::deleteLater);
QObject::connect(t, &QThread::finished, t, &QThread::deleteLater);
t->start();
The first two connect statements tie the lifetime of the generator to that of the thread, the last two clean up everything once the thread exits.
And you can of course connect to the Generator::progress signal to monitor the generation progress.

How to start a loop on a QThread

How can I start a loop on a different thread by pressing a QPushButton?
The main idea is, when pushButtonStart is clicked, start a loop on a QThread, and when pushButtonStop is clicked, stops the loop in the QThread.
The loop can be done by QTimer, for loop or while loop, but he needs a way to stop by pressing a button.
I have this code to create a new timer and set up a connection when it fires. This is in the Start code.
checkTimer = new QTimer(this);
connect( checkTimer, SIGNAL(timeout()), this, SLOT(checkTimerFired()) );
checkTimer->start(3000);
My "stop running" button sets programCreated to false, and checkTimerFired starts with this:
if (!programCreated) {
checkTimer->stop();
return;
}
That should be the Qt-specific things you need. The rest is simple C++.
To do the loop, I use QTimer, which run the slot pressButton multiple times until stop(); function of QTimer is executed. Of course, to use this method I have to recode the program, to improve the algorithm.
QTimer loop:
void MainPrograma::on_pushTurnOn_clicked()
{
tierLoop = new QTimer(this);
timerLoop->setInterval(5000);
timerLoop->setSingleShot(true);
connect(timerLoop, SIGNAL(timeout()), SLOT(on_pushTurnOn_clicked()));
QPushButton *ThirdButton = uimain->QPushButton_3;
Nmb2 = 2
Nmb4 = 4;
if(Busy==1){
ThirdButton->setEnabled(false);
}
if(Busy==0){
timerLoop->start(); //start the loop
StartFunction(Nmb2, Nmb4);
if(X==1){
ThirdButton->setEnabled(false);
}
if(X==0){
ThirdButton->setEnabled(true);
}
}
}
void MainPrograma::on_pushTurnOff_clicked()
{
timerLoop->stop(); //stop the loop
}
QTimer declaration on .h:
private:
QTimer *timerLoop;
I still do not understand how to use QThread... But the loop is already answered!

Caffe feature extraction blocks other executing threads (Qt / C++)

Background
I am developing a Qt application with three threads: main, thread1, and thread2.
main creates, starts, and displays the results of thread1 and
thread2, while also iteratively feeding them input.
thread1 performs an intensive computation (~1s) once every n
inputs, ignoring all other inputs. The majority of this time is spent on feature extraction
using the Caffe framework.
thread2 performs fast computations (~20ms) on every input. But
every n+1 inputs depend on the output of feeding input n to thread1.
During thread execution, thread1 appears to block thread2 when extracting features using the Caffe network. However, thread1 does not block thread2 during other processing steps (e.g. network input preprocessing).
At first, I thought this was caused by an unmet dependency: i.e. thread1 "blocks" thread2 because input (for example) 2n + 1 is ready to be processed by thread2 but input 2n has not been fully processed by thread1.
However, from analysing the execution flow, I noticed this "blocking" behaviour was occurring whilst dependencies were met: i.e. let n = 10, thread2 would pause execution at input 15 while thread1 was extracting Caffe features from input 20.
Question
How do I prevent thread2 from blocking thread1 during Caffe feature extraction?
Code
Below is a stripped-down version of my code, which shows the key components and logic of my program.
I have highlighted the problem in comments // !!! PROBLEM: ..., which can be found in thread1worker.cpp and featureengine.cpp.
main.cpp:
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
qRegisterMetaType<Mat>("Mat");
Camera camera; // grabs camera frame every 30ms, emitting newFrame(frame)
/* thread1 */
QThread* thread1 = new QThread();
Thread1Worker* thread1_worker = new Thread1Worker();
thread1_worker->moveToThread(thread1);
QThread::connect(&camera, SIGNAL(newFrame(Mat)),
thread1_worker, SLOT(doWork(Mat)));
QThread::connect(thread1, SIGNAL(finished()),
thread1_worker, SLOT(deleteLater()));
QThread::connect(thread1, SIGNAL(finished()),
thread1, SLOT(deleteLater()));
/* thread2 */
ImageQueue* thread2_images = new ImageQueue();
QThread::connect(camera, SIGNAL(newFrame(Mat)),
thread2_images, SLOT(add(Mat)));
QThread* thread2 = new QThread();
Thread2Worker* thread2_worker = new Thread2Worker(thread2_images);
thread2_worker->moveToThread(thread2);
QThread::connect(thread2_worker, SIGNAL(workFinished(OutputType)),
thread2_worker, SLOT(addThread1Result(OutputType)));
QThread::connect(thread2, SIGNAL(finished()),
thread2_worker, SLOT(deleteLater()));
QThread::connect(thread2, SIGNAL(finished()),
thread2, SLOT(deleteLater()));
/* start threads */
thread1->start();
thread2->start();
camera->start();
return app.exec();
}
thread1worker.cpp:
Thread1Worker::Thread1Worker()
{
thread1_interval = 10; // this is "n"
is_initialized = false;
}
void Thread1Worker::doWork(Mat frame)
{
if (!is_initialized)
initialize();
// process only every nth frame
if (!isThread1Frame())
return;
// ... break frame up into multiple image patches
// !!! PROBLEM: this call blocks thread2
vector<vector<float> > features = feature_engine->extractFeatures(patches);
// ... use features to compute output
frame_count++;
emit workFinished(output);
}
void Thread1Worker::initialize()
{
InitGoogleLogging("caffe-demo");
feature_engine = new FeatureEngine();
is_initialized = true;
}
bool Thread1Worker::isThread1Frame()
{
return frame_count % thread1_interval == 0;
}
thread2worker.cpp:
void Thread2Worker::addThread1Result(OutputType output)
{
if (!is_initialized)
initialize();
thread1_output_queue.push(output);
thread1_count++;
processFrames();
}
void Thread2Worker::processFrames()
{
size_t num_process = (thread1_count * thread1_interval) - process_count;
size_t num_queue = thread2_images->size();
for (size_t i = 0; i < num_process && i < num_queue; i++)
{
Mat frame = thread2_images->get();
if (isThread1Frame()
{
curr_result = thread1_output_queue.front();
thread1_output_queue.pop();
}
else
{
curr_result = propagator->propagate(prev_result);
}
// update
prev_result = curr_result;
emit resultReady(curr_result);
}
}
void Thread2Worker::initialize()
{
propagator = new Propagator();
is_initialized = true;
}
bool Thread2Worker::isThread1Frame()
{
return process_count % thread1_interval == 0;
}
featureengine.cpp:
vector<vector<float> > FeatureEngine::extractFeatures(const vector<Mat>& images)
{
// setup Caffe network for feature extraction:
Blob<float>* input_layer = net->input_blobs()[0];
int num_images = images.size();
int height = input_geometry.height;
int width = input_geometry.width;
input_layer->Reshape(num_images, num_channels, height, width);
net->Reshape();
vector<Mat> input_channels;
wrapInputLayer(input_channels);
preprocess(images, &input_channels);
// !!! PROBLEM: this ~1s computation blocks thread2
// details: https://github.com/BVLC/caffe/blob/master/src/caffe/net.cpp#L594
net->ForwardPrefilled();
// copy Caffe network output to features vector
vector<vector<float> > features;
// ...
return features;
}

Qt change picture on timer

I'm trying to change the image on QLabel in Qt.
At first, I did the basic set image as follows:
void MainWindow::setMainDisplayNew(QString imageName){
QPixmap pix7 = imageName;
QPixmap pix8 = pix7.scaled(QSize(720,480), Qt::KeepAspectRatio);
ui->mainDisplay->setStyleSheet(imageName);
ui->mainDisplay->setPixmap(pix8);
}
Now I want to change this so I can pass 2 arrays. List of images and duration they should appear for and I want the display to show them for the indicated duration.
void MainWindow::setMainDisplay(QString imageName[], int size)
{
for(unsigned int i=0; i<size; i++)
{
QTimer * timer = new QTimer(this);
timer->setSingleShot(true);
connect(timer, &QTimer::timeout, [=](){
setMainDisplayNew(imageName[i]);
timer->deleteLater(); // ensure we cleanup the timer
});
timer->start(3000);
}
}
EDIT
With the help of the responses, I reached the above code. I am sending the 3 images. It is display the final image after 3 seconds and stays as is... Any help?
while(true){
This is your problem. Qt is an event-driven framework. The while(true) prevents events from being processed. Such events include the timeout from the QTimer and updating of the GUI. You need to allow the function to exit.
In addition, you're not cleaning up your timers, so you're leaking memory every time you enter the function (although that's currently only once!). You can clean up with a call to deleteLater.
Using C++ 11, it would be something like this: -
for(int i=0; i<mySize; i++)
{
QTimer * timer = new QTimer(this);
timer->setSingleShot(true);
connect(timer, &QTimer::timeout, [=](){
setMainDisplayNew(imageName[i]);
timer->deleteLater(); // ensure we cleanup the timer
});
timer->start(duration[i]);
}

Something is incorrectly set when try to start new thread

I'm trying to create a "responsive gui", which basically means that I have an app, and on the main window there is a button. After I press this button I want the "progress bar window" to get displayed which will show the progress of the work being done, and of course this work is being done in separate thread.
Unfortunately my approach with starting a new thread in ctor of this progress_bar window doesn't seems to work and I got frozen gui.
Here is the link to this project so you can download it and run without the need for copying and pasting anything: http://www.mediafire.com/?w9b2eilc7t4yux0
Could anyone please tell me what I'm doing wrong and how to fix it?
EDIT
progress_dialog::progress_dialog(QWidget *parent) :
QDialog(parent)
{/*this is this progress dialog which is displayed from main window*/
setupUi(this);
working_thread_ = new Threaded;
connect(working_thread_,SIGNAL(counter_value(int)),progressBar,SLOT(setValue(int)),Qt::QueuedConnection);
working_thread_->start();//HERE I'M STARTING THIS THREAD
}
/*this is run fnc from the threaded class*/
void Threaded::run()
{
unsigned counter = 0;
while(true)
{
emit counter_value(counter);
counter = counter + 1 % 1000000;
}
}
Independently from the fact that tight looping is bad, you should limit the rate at which you make changes to the main GUI thread: the signals from your thread are queued as soon they are emitted on the main thread event loop, and as the GUI can't update that fast, repaint events are queued rather than executed in real time, which freezes the GUI.
And anyways updating the GUI faster than the screen refresh rate is useless.
You could try something like this:
void Threaded::run()
{
QTime time;
time.start();
unsigned counter = 0;
// initial update
emit counter_value(counter);
while(true)
{
counter = (counter + 1) % 1000000;
// 17 ms => ~ 60 fps
if(time.elapsed() > 17) {
emit counter_value(counter);
time.restart();
}
}
}
Do you try to start the thread with a parent object?