Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Playing Gif Synchronously while Other Process is Running



  • Hello,

    What I am trying to do with my gui application is;
    I would like to play a gif when user click a button which calls a function. And this function read images in same folder and find their contrast value with Laplacian method for comparing which image is more focused.
    Anyway, I intend to play a gif movie in label of the gui while this procedure is running in background.

    I tried QApplication::processEvents(); which does not work as I wanted. Movie starts after procedure is finished.

    I am confused if I should use;
    "<QtConcurrentRun> - Asynchronous Run" from here.
    or I need to create another thread for running calling void here

    What I have;

    Main.cpp

    #include "screen.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        screen w;
        w.show();
    
        return a.exec();
    }
    

    screen.cpp:

    #include "screen.h"
    #include "ui_screen.h"
    #include <iostream>
    #include <algorithm>
    #include <cmath>
    #include <iomanip>
    #include <stdlib.h>
    #include <stdio.h>
    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    #include <QString>
    #include <QMovie>
    
    
    
    
    using namespace cv;
    using namespace std;
    
    screen::screen(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::screen)
    {
        ui->setupUi(this);
        movie = new QMovie("loading.gif");
        ui->splash->setMovie(movie);
        connect(ui->pushButton, SIGNAL(clicked()), movie, SLOT(start()));
    
    }
    
    screen::~screen()
    {
        delete ui;
    }
    
    double modifiedLaplacian(const cv::Mat& src)
    {
        cv::Mat M = (Mat_<double>(3, 1) << -1, 2, -1);
        cv::Mat G = cv::getGaussianKernel(3, -1, CV_64F);
    
        cv::Mat Lx;
        cv::sepFilter2D(src, Lx, CV_64F, M, G);
    
        cv::Mat Ly;
        cv::sepFilter2D(src, Ly, CV_64F, G, M);
    
        cv::Mat FM = cv::abs(Lx) + cv::abs(Ly);
    
        double focusMeasure = cv::mean(FM).val[0];
        return focusMeasure;
    }
    
    void screen::on_pushButton_clicked()
    {
    processimages();
    QApplication::processEvents();
    
    }
    
    void screen::processimages(){
        vector<string> paths;
        string path;
        double result_of_laplacian;
        for (int i=0; i<10; i++) {  // load images in same folder
            path=std::to_string(i)+".png";
            paths.push_back(path);
    
        }
    
        for (int i =0; i<10; i++){
        cout<<"am in "<<endl;
        Mat image=imread(paths[i]);
        result_of_laplacian=modifiedLaplacian(image);
        cout<<"laplacian method:"<<result_of_laplacian<<endl;
    
        }
    }
    

    Thank you for any suggestions or help.


  • Lifetime Qt Champion

    Hi,

    You are blocking the event loop while doing your processing.

    QtConcurrent::run would indeed be a good alternative to move your processing to another thread.



  • @SGaist said in Playing Gif Synchronously while Other Process is Running:

    QtConcurrent::run

    Thank you for the reply. I have tried QtConcurrent::run, it works just fine now.
    Here how i call the function now;

    QFuture<void> future = QtConcurrent::run(this,&screen::processimages);
    

    What I want to learn now, How can i this function If the function has it's member with QtConcurrent.

    For instance; I have this void;

    void screen::processimages(vector<strings> paths) { ... do something ..}
    
    

    I have tried this;

    vector<strings> allthepaths;
    QFuture<void> future = QtConcurrent::run(this,&screen::processimages, allthepaths);
    

    It did not work
    How can i call this function now?
    Thanks


  • Moderators

    @qtross said in Playing Gif Synchronously while Other Process is Running:

    I have tried this;

    vector<strings> allthepaths;
    QFuture<void> future = QtConcurrent::run(this,&screen::processimages, allthepaths);
    

    It did not work
    How can i call this function now?
    Thanks

    that should work, probably, the type vector and strings is not registered correctly in the meta system.

    If you use QList<QString> it should work fine out of the box.



  • @J.Hilk Yes you're right that works. But in big images which cause long progress it just cancels and i need to run 2-3 times to make it working. I did not understand why that happens. Maybe i am doing something silly. I found this page I guess i need to move this thread to another thread and give some signals for finishing this loop, in long processes it just does not finish the background thread in first attempt.

    Thanks


  • Moderators

    @qtross
    it shouldn't simply cancel.

    Can you post some more of your code, or better yet, a simply minimal compileable example for us to test ourselves



  • @J.Hilk Hi again, I have found what the problem was. I can't share all of my codes codes but I will share how to solve it. While my function which is in another thread works still in process, my main thread calls the result and paint it in the label. Therefore I saw my final result in first or third attempt which was luck I guess.
    I solved it with emitting finished signal at the end of the qtconcurrent function.

    Here how I do that, which may be helpful to others;

    I created a signal function in header file;

    void threadfinished();
    

    And added at end of the qtconcurrent function;

    emit threadfinished();
    

    and connect function after thread;

    connect(this, &screen::threadfinished, this, &screen::startafterthreadfinished);
    

    Thanks


Log in to reply