Qt - SIGNAL & SLOT 没有从工人阶级更新我在主窗口中的 QLabel
Posted
技术标签:
【中文标题】Qt - SIGNAL & SLOT 没有从工人阶级更新我在主窗口中的 QLabel【英文标题】:Qt - SIGNAL & SLOT are not updating my QLabel in mainwindow from a worker class 【发布时间】: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);
我该如何解决这个问题?
谢谢。
【问题讨论】:
【参考方案1】:在您的代码中,doWork()
函数从Worker
的构造函数中调用,构造函数在主线程中调用(在Worker* worker= new Worker;
行中完成)。
当然,这不是你想要做的,因为它会导致主线程在到达connect
调用之前执行doWork()
中的for
循环。
您应该将线程的started()
信号连接到doWork()
槽,而不是从Worker
的构造函数调用doWork()
,然后在将Worker
对象移动到新线程后调用thread->start()
。这将利用 Qt 跨线程信号在新线程启动时立即调用 doWork()
。
你的代码应该是这样的:
#include <QtWidgets>
//QThread wrapper for safe destruction
//see http://***.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 layoutthis;
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);
【讨论】:
以上是关于Qt - SIGNAL & SLOT 没有从工人阶级更新我在主窗口中的 QLabel的主要内容,如果未能解决你的问题,请参考以下文章