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
Forum Updated to NodeBB v4.3 + New Features

Unable to send signal from mainwindow to working thread

Scheduled Pinned Locked Moved Solved General and Desktop
8 Posts 4 Posters 2.7k Views 2 Watching
  • 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