【问题标题】:Qt - SIGNAL & SLOT are not updating my QLabel in mainwindow from a worker classQt - SIGNAL & SLOT 没有从工人阶级更新我在主窗口中的 QLabel
【发布时间】:2016-12-16 20:20:14
【问题描述】:

我应用了一个在 Qt 5.7 中使用线程的 C++ 示例。万事俱备,除了两件事:

1- 我使用 Signal & Slot 在主窗体中更新我的标签。问题是没有效果。真的,我不知道问题出在哪里。

2- 循环工作正常,但是当我退出程序时,我看到(通过“应用程序输出”)循环仍然有效(我认为这与启动的线程有关)。

这是我的小例子:


主窗口.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

主窗口.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

#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);
    }
}

我该如何解决这个问题?

谢谢。

【问题讨论】:

    标签: c++ multithreading qt loops signals-slots


    【解决方案1】:

    在您的代码中,doWork() 函数从Worker 的构造函数中调用,构造函数在主线程中调用(在Worker* worker= new Worker; 行中完成)。

    当然,这不是你想要做的,因为它会导致主线程在到达connect 调用之前执行doWork() 中的for 循环。

    您应该将线程的started() 信号连接到doWork() 槽,而不是从Worker 的构造函数调用doWork(),然后在将Worker 对象移动到新线程后调用thread-&gt;start()。这将利用 Qt 跨线程信号在新线程启动时立即调用 doWork()

    你的代码应该是这样的:

    #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"
    

    【讨论】:

      【解决方案2】:

      我按照@Mike 先生的评论解决了我的问题。

      简单地说,我从讲师那里删除了 doWork() 函数。然后,我在线程的 started() SIGNAL 和 worker 的 doWork() SLOT 之间添加了新的连接。

      所以这些是变化:


      主窗口.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

      #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);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-09-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多