简体   繁体   中英

Qt signal and slots do not work if called from QRunnable or another thread

I am trying to learn how to use Multi-threading in Qt and put it to use in QtWidget applications. So I have setup this simple test case.

MainWindow This form has some buttons and each button will execute another form (a Dialog for that matter).

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    connect(ui->btnShowCalibrationDialog, &QPushButton::clicked,
            this, [&](){

        CalibrationDialog dlg;
        dlg.exec();
    });
}

MainWindow::~MainWindow()
{
    delete ui;
}

CalibrationDialog This dialog has a QPushButton and a QTextEdit . When the button is clicked I will run a QRunnable class (comes next!)

calibrationdialog.h (I have spared you the includes and guards!)

    class CalibrationDialog : public QDialog
    {
        Q_OBJECT

    public:
        explicit CalibrationDialog(QWidget *parent = nullptr);
        ~CalibrationDialog();

    public slots:
        void onBeginWorkRequested();
        void onReceiveData(int data);

    private:
        Ui::CalibrationDialog *ui;
    };

calibrationdialog.cpp

#include "worker.h"

CalibrationDialog::CalibrationDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::CalibrationDialog)
{
    ui->setupUi(this);

    connect(ui->btnBegin, &QPushButton::clicked,
            this, &CalibrationDialog::onBeginWorkRequested);
}

CalibrationDialog::~CalibrationDialog()
{
    delete ui;
}

void CalibrationDialog::onBeginWorkRequested()
{
    qDebug() << "CalibrationDialog::onBeginWorkRequested()" << "on" << QThread::currentThreadId();
    Worker* worker = new Worker();
    QThreadPool* pool = QThreadPool::globalInstance();
    connect(worker, &Worker::reportProgress,
            this, &CalibrationDialog::onReceiveData);
    pool->start(worker);
    pool->waitForDone();
}

void CalibrationDialog::onReceiveData(int data)
{
    ui->teResults->append(QString::number(data));
    ui->teResults->ensureCursorVisible();
}

Worker And this is some runnable...I want to report the progress so that is shows up in the textedit of the dialog in a reponsive manner!

worker.h

class Worker : public QObject, public QRunnable
{
    Q_OBJECT

public:
    explicit Worker(QObject *parent = nullptr);
    void run() override;

private:
    int mProgress = 0;

signals:
    void reportProgress(int progress);

};

worker.cpp

Worker::Worker(QObject *parent) : QObject(parent)
{

}

void Worker::run()
{
    qDebug() << "Worker is running #" << QThread::currentThreadId();
    while(true) {
        mProgress += 100;
        emit reportProgress(mProgress);
        QThread::msleep(500);
    }
}

I see in the debugger that control goes in to the while loop...but the signal is not being handled by the dialog! I mean the textedit stays empty!

I tried to read documentationand search online...I came to the conclusion that my problem lies in the waste land of thread affinity....but I have no idea if that is the case and if that is, how to solve it. Please assist!

remove pool->waitForDone(); , never use waitForX methods in a GUI since they are blocking preventing signals from doing their job.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM