繁体   English   中英

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

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

我在Qt 5.7中应用了一个使用线程的C ++示例。 除以下两点外,其他一切都很好:

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

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

这是我的小例子:


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

主窗口

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

工人

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

我怎样才能解决这个问题?

谢谢。

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

当然,这不是您要执行的操作,因为这将导致主线程甚至在进入connect调用之前在doWork()执行for循环。

而不是从Worker的构造函数调用doWork() ,您应该将线程的started()信号连接到doWork()插槽,然后在将Worker对象移动到新线程之后调用thread->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"

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

简而言之,我从讲师中删除了doWork()函数。 然后,我在线程的started()信号和工作者的doWork()插槽之间添加了新的连接。

这些就是变化:


主窗口

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

暂无
暂无

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

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