简体   繁体   English

Qt-SIGNAL&SLOT没有从工人阶级的主窗口中更新我的QLabel

[英]Qt - SIGNAL & SLOT are not updating my QLabel in mainwindow from a worker class

I applied an C++ example of working with threads in Qt 5.7. 我在Qt 5.7中应用了一个使用线程的C ++示例。 All things are good except two things: 除以下两点外,其他一切都很好:

1- I used Signal & Slot to update my label in the main form. 1-我使用Signal&Slot来更新主表单中的标签。 the problem is that is no effect. 问题是那没有效果。 Really, I don't know where is the issue. 真的,我不知道问题出在哪里。

2- The loop works fine, but when I exit my program I see (throught the "Application Output") that the loop still work (I think that's related with the started thread). 2-循环工作正常,但是当我退出程序时(通过“应用程序输出”),我看到该循环仍然有效(我认为这与启动的线程有关)。

This my little example: 这是我的小例子:


mainwindow.h mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();  

private slots:
    void on_pushButton_clicked();
    void updateLabelText(const QString TheString);

private:
    Ui::MainWindow *ui;

};

#endif // MAINWINDOW_H

mainwindow.cpp 主窗口

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "worker.h"

//#include <QDebug>
#include <QThread>

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

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

void MainWindow::on_pushButton_clicked()
{
    QThread *workerThread = new QThread;
    Worker *worker  = new Worker;
    worker->moveToThread(workerThread);
    connect(worker, SIGNAL(sendText(const QString)), this, SLOT(updateLabelText(QString)));
    workerThread->start();
}

void  MainWindow::updateLabelText(const QString TheString)
{
    ui->label->setText(TheString);
}

worker.h 工人

#ifndef WORKER_H
#define WORKER_H

#include <QObject>

class Worker : public QObject
{
    Q_OBJECT

public:
    explicit Worker();

public slots:
    void doWork();

signals:
  void sendText(const QString);

};

#endif // WORKER_H

worker.cpp worker.cpp

#include "worker.h"
#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QDebug>
#include <QThread>
#include <QMessageBox>
#include <QApplication>

Worker::Worker()
{
    doWork();
}

void Worker::doWork()
{
    for (int i = 0; i<999999; i++) {
        emit sendText(QString::number(i));
        qDebug() << "The number is : " + QString::number(i);
        qApp->processEvents();
        //QThread::msleep(5);
    }
}

How can I fix this? 我怎样才能解决这个问题?

Thanks. 谢谢。

In your code, doWork() function is called from the Worker 's constructor, the constructor is invoked in the main thread (that is done in the line Worker* worker= new Worker; ). 在您的代码中,从Worker的构造函数调用doWork()函数,该构造函数在主线程中调用(在Worker* worker= new Worker; )。

Of course, that is not what you meant to do, since it will cause the main thread to execute the for loop in doWork() before even reaching into the connect call. 当然,这不是您要执行的操作,因为这将导致主线程甚至在进入connect调用之前在doWork()执行for循环。

Instead of calling doWork() from the Worker 's constructor, you should connect the thread's started() signal to doWork() slot, then call thread->start() after moving the Worker object to the new thread. 而不是从Worker的构造函数调用doWork() ,您应该将线程的started()信号连接到doWork()插槽,然后在将Worker对象移动到新线程之后调用thread->start() This will leverage Qt cross-thread signals to invoke doWork() in the new thread as soon as it starts. 这将利用Qt跨线程信号在新线程启动时立即调用doWork()

Here is how your code should look like: 代码如下所示:

#include <QtWidgets>

//QThread wrapper for safe destruction
//see http://stackoverflow.com/a/19666329
class Thread : public QThread{
    using QThread::run; //final
public:
    Thread(QObject* parent= nullptr): QThread(parent){}
    ~Thread(){ quit(); wait();}

};

class Worker : public QObject{
    Q_OBJECT
public:
    explicit Worker(QObject* parent= nullptr): QObject(parent){}
    ~Worker()= default;

    Q_SIGNAL void sendText(QString text);
    Q_SIGNAL void workFinished();

    Q_SLOT void doWork(){
        for (int i = 0; i<1000; i++) {
            emit sendText(QString::number(i));
            QThread::msleep(5);
        }
        emit workFinished();
    }
};

class Widget : public QWidget{
    Q_OBJECT
public:
    explicit Widget(QWidget* parent= nullptr): QWidget(parent){
        layout.addWidget(&buttonWork);
        layout.addWidget(&label);

        connect(&buttonWork, &QPushButton::clicked,
                this, &Widget::buttonWorkClicked);

    }
    ~Widget()= default;

    Q_SLOT void buttonWorkClicked(){
        Thread* thread= new Thread(this);
        Worker* worker= new Worker;
        worker->moveToThread(thread);
        //invoke doWork as soon as the thread is started
        connect(thread, &QThread::started, worker, &Worker::doWork);
        connect(worker, &Worker::sendText, this, &Widget::updateLabelText);
        //quit the thread when work is finished
        connect(worker, &Worker::workFinished, thread, &QThread::quit);
        //destroy thread and worker object when work is finished
        connect(thread, &QThread::finished, thread, &QObject::deleteLater);
        connect(thread, &QThread::finished, worker, &QObject::deleteLater);
        //start the thread
        thread->start();
    }

    Q_SLOT void updateLabelText(QString text){
        label.setText(text);
    }

private:
    QVBoxLayout layout{this};
    QPushButton buttonWork{"Work"};
    QLabel label{"No work yet"};
};

int main(int argc, char* argv[]){
    QApplication a(argc, argv);

    Widget w;
    w.show();

    return a.exec();
}

#include "main.moc"

I solved my problem by following the comment of Mr @Mike. 我按照@Mike先生的评论解决了我的问题。

Simply, I removed the doWork() function from the instructor. 简而言之,我从讲师中删除了doWork()函数。 Then, I added new connection between the thread's started() SIGNAL and worker's doWork() SLOT. 然后,我在线程的started()信号和工作者的doWork()插槽之间添加了新的连接。

So thes are the changes: 这些就是变化:


mainwindow.cpp 主窗口

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "worker.h"

#include <QThread>

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

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

void MainWindow::on_pushButton_clicked()
{
    QThread *workerThread = new QThread;
    Worker *worker  = new Worker;
    connect(workerThread, SIGNAL(started()), worker, SLOT(doWork()),Qt::QueuedConnection);
    connect(worker, SIGNAL(sendText(const QString)), this, SLOT(updateLabelText(const QString)),Qt::QueuedConnection);
    worker->moveToThread(workerThread);
    workerThread->start();
}
void  MainWindow::updateLabelText(const QString TheString)
{
    ui->label->setText(TheString);
}

worker.cpp worker.cpp

#include "worker.h"
#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QDebug>
#include <QThread>
#include <QMessageBox>
#include <QApplication>

Worker::Worker()
{
    doWork();
}

void Worker::doWork()
{
    for (int i = 0; i<999999; i++) {
        emit sendText(QString::number(i));
        qDebug() << "The number is : " + QString::number(i);
        qApp->processEvents();
        QThread::msleep(5);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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