[英]Qt - SIGNAL & SLOT are not updating my QLabel in mainwindow from a worker class
我在Qt 5.7中應用了一個使用線程的C ++示例。 除以下兩點外,其他一切都很好:
1-我使用Signal&Slot來更新主表單中的標簽。 問題是那沒有效果。 真的,我不知道問題出在哪里。
2-循環工作正常,但是當我退出程序時(通過“應用程序輸出”),我看到該循環仍然有效(我認為這與啟動的線程有關)。
這是我的小例子:
#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
#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);
}
#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.