Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Unable to send signal from mainwindow to working thread

Unable to send signal from mainwindow to working thread

Scheduled Pinned Locked Moved Solved General and Desktop
8 Posts 4 Posters 2.7k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    magicstar
    wrote on last edited by
    #1

    I wish to display videos using OpenCV using multithreading. I have followed [this link] and results are as expected. Here is code snippet.

    class Worker : public QObject
    {
        Q_OBJECT
    public:
        Worker(QString path, int id);
        ~Worker();
    
    public slots:
        void readVideo(QString path = "");
        void get_from_main(QString path);
    
    signals:
        // frame and index of label which frame will be displayed
        void frameFinished(cv::Mat frame, int index);
    
        void finished(int index);
    
    private:
        QString filepath;
        int index;
    };
    
    //worker.cpp
    #include "worker.h"
    #include <QDebug>
    #include <QThread>
    #include <QTime>
    Worker::Worker(QString path, int id) : filepath(path), index(id)
    {
    
    }
    
    Worker::~Worker()
    {
    }
    
    void Worker::get_from_main(QString path)
    {
          qDebug() << "updating";
    }
    
    void Worker::readVideo(QString path)
    {
        if (path.length() > 0)
            filepath = path;
    
        cv::VideoCapture cap(filepath.toStdString());
    
        if (! cap.isOpened())
        {
            qDebug() << "Can't open video file " << filepath;
            emit finished(index);
            return;
        }
    
        cv::Mat frame;
        while (true)
        {
            cap >> frame;
            if (frame.empty())
            {
                frame = cv::Mat(cv::Size(720, 576), CV_8UC3, cv::Scalar(192, 0, 0));
                emit frameFinished(frame, index);
                break;
            }
    
    
            emit frameFinished(frame.clone(), index);
            QThread::msleep(30);
        }
    
        emit finished(index);
    }
    
    //mainwindow.h
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <opencv2/opencv.hpp>
    
    #include "worker.h"
    
    #define MAX_NUM_CAM 8
    
    namespace Ui {
    class MainWindow;
    }
    
    class QThread;
    class QLabel;
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
        void init();
    
    private slots:
        void displayFrame(cv::Mat frame, int index);
        void file_open_clicked();
    
    signals:
    send_to_worker(QString path);
    
    
    private:
        Ui::MainWindow *ui;
    
        int numCams;
        QLabel *labels[MAX_NUM_CAM];
        QThread* threads[MAX_NUM_CAM];
        Worker* workers[MAX_NUM_CAM];
    };
    
    #endif // MAINWINDOW_H
    
    
    //mainwindow.cpp
    
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    #include <QDebug>
    #include <QThread>
    #include <QLabel>
    #include <QGridLayout>
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        qRegisterMetaType< cv::Mat >("cv::Mat");
    
        qDebug() << "Main thread " << QThread::currentThreadId();
        init();
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::init()
    {
        QGridLayout *grid = new QGridLayout;
        int numCols = 2;
    
        numCams = 4;
    
        int row = 0, col = 0;
        for (int i = 0; i < numCams; i++)
        {
            labels[i] = new QLabel;
    
            row = i / numCols;
            col = i % numCols;
            grid->addWidget(labels[i], row, col);
    
    
            threads[i] = new QThread;
            workers[i] = new Worker(QString("/home/shang/Videos/%1.mp4").arg(i+1), i);
            workers[i]->moveToThread(threads[i]);
    
            connect(workers[i], SIGNAL(frameFinished(cv::Mat, int)), this, SLOT(displayFrame(cv::Mat,int)));
            connect(threads[i], SIGNAL(started()), workers[i], SLOT(readVideo()));
    
            connect(workers[i], SIGNAL(finished(int)), threads[i], SLOT(quit()));
            connect(workers[i], SIGNAL(finished(int)), workers[i], SLOT(deleteLater()));
    
            connect(threads[i], SIGNAL(finished()), threads[i], SLOT(deleteLater()));
    
            threads[i]->start();
        }
    
        this->centralWidget()->setLayout(grid);
    
    }
    
    void MainWindow::file_open_clicked(){
           QString Path = QFileDialog::getSaveFileName( this,tr("OpenVideo"),"","Video (*.avi)");
        if(Path.isEmpty())
            return;
         view =3; 
        connect(this, SIGNAL(send_to_worker(QString)),workers[view], SLOT(get_from_main(QString)));
        emit this->send_to_worker(recorder_Path);
    }
    
    void MainWindow::displayFrame(cv::Mat frame, int index)
    {
        QPixmap p = QPixmap::fromImage(QImage(frame.data, frame.cols, frame.rows, frame.step, QImage::Format_RGB888).rgbSwapped());
        p = p.scaled(QSize(frame.cols/2, frame.rows/2));
        labels[index]->setPixmap(p);
    }
    

    However, slot get_from_main is never triggered. May I please know how to correctly implement QThreading.

    (https://stackoverflow.com/questions/29338250/qt-opencv-play-videos-with-stdthread)

    JKSHJ 1 Reply Last reply
    0
    • mrjjM Offline
      mrjjM Offline
      mrjj
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi
      Code does look valid.
      Did you check the connect statements that they all return TRUE ?

      M 1 Reply Last reply
      1
      • mrjjM mrjj

        Hi
        Code does look valid.
        Did you check the connect statements that they all return TRUE ?

        M Offline
        M Offline
        magicstar
        wrote on last edited by
        #3

        @mrjj
        Thanks for the reply.

        How do I check if they return true?
        I am indeed able to view video. only facing problem with
        connect(this, SIGNAL(send_to_worker(QString)),workers[view], SLOT(get_from_main(QString)));

        1 Reply Last reply
        0
        • Christian EhrlicherC Offline
          Christian EhrlicherC Offline
          Christian Ehrlicher
          Lifetime Qt Champion
          wrote on last edited by
          #4

          The slot can't be called since the thread never reaches it's eventloop. So no chance to retrieve the signal and pass it to your slot.

          Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
          Visit the Qt Academy at https://academy.qt.io/catalog

          M 1 Reply Last reply
          2
          • Christian EhrlicherC Christian Ehrlicher

            The slot can't be called since the thread never reaches it's eventloop. So no chance to retrieve the signal and pass it to your slot.

            M Offline
            M Offline
            magicstar
            wrote on last edited by
            #5

            @Christian-Ehrlicher ,
            can you explain it in detail. Also, is there any other way to modify private variable "path" of worker class

            1 Reply Last reply
            0
            • Christian EhrlicherC Offline
              Christian EhrlicherC Offline
              Christian Ehrlicher
              Lifetime Qt Champion
              wrote on last edited by
              #6

              What detail? As I said an eventloop is needed to deliver signals to slots. You don't run an eventloop in your thread and therefore the slot gets no called. See also http://doc.qt.io/qt-5/qthread.html#details
              It's not forbidden to call a function of an object in another thread directly. You must only take care that this access is synchronized e.g. with a semaphore. See http://doc.qt.io/qt-5/threads-synchronizing.html for more information.

              Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
              Visit the Qt Academy at https://academy.qt.io/catalog

              1 Reply Last reply
              0
              • M magicstar

                I wish to display videos using OpenCV using multithreading. I have followed [this link] and results are as expected. Here is code snippet.

                class Worker : public QObject
                {
                    Q_OBJECT
                public:
                    Worker(QString path, int id);
                    ~Worker();
                
                public slots:
                    void readVideo(QString path = "");
                    void get_from_main(QString path);
                
                signals:
                    // frame and index of label which frame will be displayed
                    void frameFinished(cv::Mat frame, int index);
                
                    void finished(int index);
                
                private:
                    QString filepath;
                    int index;
                };
                
                //worker.cpp
                #include "worker.h"
                #include <QDebug>
                #include <QThread>
                #include <QTime>
                Worker::Worker(QString path, int id) : filepath(path), index(id)
                {
                
                }
                
                Worker::~Worker()
                {
                }
                
                void Worker::get_from_main(QString path)
                {
                      qDebug() << "updating";
                }
                
                void Worker::readVideo(QString path)
                {
                    if (path.length() > 0)
                        filepath = path;
                
                    cv::VideoCapture cap(filepath.toStdString());
                
                    if (! cap.isOpened())
                    {
                        qDebug() << "Can't open video file " << filepath;
                        emit finished(index);
                        return;
                    }
                
                    cv::Mat frame;
                    while (true)
                    {
                        cap >> frame;
                        if (frame.empty())
                        {
                            frame = cv::Mat(cv::Size(720, 576), CV_8UC3, cv::Scalar(192, 0, 0));
                            emit frameFinished(frame, index);
                            break;
                        }
                
                
                        emit frameFinished(frame.clone(), index);
                        QThread::msleep(30);
                    }
                
                    emit finished(index);
                }
                
                //mainwindow.h
                #ifndef MAINWINDOW_H
                #define MAINWINDOW_H
                
                #include <QMainWindow>
                #include <opencv2/opencv.hpp>
                
                #include "worker.h"
                
                #define MAX_NUM_CAM 8
                
                namespace Ui {
                class MainWindow;
                }
                
                class QThread;
                class QLabel;
                
                class MainWindow : public QMainWindow
                {
                    Q_OBJECT
                
                public:
                    explicit MainWindow(QWidget *parent = 0);
                    ~MainWindow();
                
                    void init();
                
                private slots:
                    void displayFrame(cv::Mat frame, int index);
                    void file_open_clicked();
                
                signals:
                send_to_worker(QString path);
                
                
                private:
                    Ui::MainWindow *ui;
                
                    int numCams;
                    QLabel *labels[MAX_NUM_CAM];
                    QThread* threads[MAX_NUM_CAM];
                    Worker* workers[MAX_NUM_CAM];
                };
                
                #endif // MAINWINDOW_H
                
                
                //mainwindow.cpp
                
                #include "mainwindow.h"
                #include "ui_mainwindow.h"
                
                #include <QDebug>
                #include <QThread>
                #include <QLabel>
                #include <QGridLayout>
                
                MainWindow::MainWindow(QWidget *parent) :
                    QMainWindow(parent),
                    ui(new Ui::MainWindow)
                {
                    ui->setupUi(this);
                    qRegisterMetaType< cv::Mat >("cv::Mat");
                
                    qDebug() << "Main thread " << QThread::currentThreadId();
                    init();
                }
                
                MainWindow::~MainWindow()
                {
                    delete ui;
                }
                
                void MainWindow::init()
                {
                    QGridLayout *grid = new QGridLayout;
                    int numCols = 2;
                
                    numCams = 4;
                
                    int row = 0, col = 0;
                    for (int i = 0; i < numCams; i++)
                    {
                        labels[i] = new QLabel;
                
                        row = i / numCols;
                        col = i % numCols;
                        grid->addWidget(labels[i], row, col);
                
                
                        threads[i] = new QThread;
                        workers[i] = new Worker(QString("/home/shang/Videos/%1.mp4").arg(i+1), i);
                        workers[i]->moveToThread(threads[i]);
                
                        connect(workers[i], SIGNAL(frameFinished(cv::Mat, int)), this, SLOT(displayFrame(cv::Mat,int)));
                        connect(threads[i], SIGNAL(started()), workers[i], SLOT(readVideo()));
                
                        connect(workers[i], SIGNAL(finished(int)), threads[i], SLOT(quit()));
                        connect(workers[i], SIGNAL(finished(int)), workers[i], SLOT(deleteLater()));
                
                        connect(threads[i], SIGNAL(finished()), threads[i], SLOT(deleteLater()));
                
                        threads[i]->start();
                    }
                
                    this->centralWidget()->setLayout(grid);
                
                }
                
                void MainWindow::file_open_clicked(){
                       QString Path = QFileDialog::getSaveFileName( this,tr("OpenVideo"),"","Video (*.avi)");
                    if(Path.isEmpty())
                        return;
                     view =3; 
                    connect(this, SIGNAL(send_to_worker(QString)),workers[view], SLOT(get_from_main(QString)));
                    emit this->send_to_worker(recorder_Path);
                }
                
                void MainWindow::displayFrame(cv::Mat frame, int index)
                {
                    QPixmap p = QPixmap::fromImage(QImage(frame.data, frame.cols, frame.rows, frame.step, QImage::Format_RGB888).rgbSwapped());
                    p = p.scaled(QSize(frame.cols/2, frame.rows/2));
                    labels[index]->setPixmap(p);
                }
                

                However, slot get_from_main is never triggered. May I please know how to correctly implement QThreading.

                (https://stackoverflow.com/questions/29338250/qt-opencv-play-videos-with-stdthread)

                JKSHJ Offline
                JKSHJ Offline
                JKSH
                Moderators
                wrote on last edited by
                #7

                @magicstar said in Unable to send signal from mainwindow to working thread:

                while (true)

                This is an infinite loop. It causes Worker::readVideo() to block forever and never return. When the function never returns, the event loop never gets the chance to process any more signals. (In other words, a thread that is running an infinite loop cannot run any slots).

                A thread can only have run an infinite loop, or it can only run an event loop. It cannot run both.

                Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                M 1 Reply Last reply
                3
                • JKSHJ JKSH

                  @magicstar said in Unable to send signal from mainwindow to working thread:

                  while (true)

                  This is an infinite loop. It causes Worker::readVideo() to block forever and never return. When the function never returns, the event loop never gets the chance to process any more signals. (In other words, a thread that is running an infinite loop cannot run any slots).

                  A thread can only have run an infinite loop, or it can only run an event loop. It cannot run both.

                  M Offline
                  M Offline
                  magicstar
                  wrote on last edited by
                  #8

                  @JKSH , @Christian-Ehrlicher , Thanks

                  1 Reply Last reply
                  0

                  • Login

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • Users
                  • Groups
                  • Search
                  • Get Qt Extensions
                  • Unsolved