前言
在Qt多线程编程过程中,常常会遇到不同线程之间数据传递的需求。此博客则是通过一个简单的例子——子线程任务处理过程中更新主线程进度条,来介绍线程间数据传递的解决方法
任务需求
由于程序存在耗时的操作,因此将此耗时的操作放在一个新的线程中从而避免界面“假死”。但是在耗时操作执行过程中,为了给用户友好的交互体验,需要利用进度条(ProgressBar)给用户展示程序实时处理的进度,这就涉及到在子线程中耗时操作的处理进度变量如何传递到界面主线程中
解决方案
定义信号函数
在子线程对应的类中定义信号函数,用于传递子线程任务进度变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class workThread : public QObject { Q_OBJECT public: workThread(QObject* parent = nullptr); ~workThread(); bool m_bStart;
public slots: void start1(); void doWork();
signals: void workFinished(); void workStart(); void updateProgress(const int nNum); };
|
定义相应的槽函数
在主线程类中定义更新进度条的槽函数,其中更新所需的变量信息通过上一步子线程的信号函数进行传递
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class QtWidgetsApplication1 : public QWidget { Q_OBJECT
public: QtWidgetsApplication1(QWidget *parent = Q_NULLPTR); void updateProgress(int nNum);
private slots: void on_pushButton_clicked();
private: Ui::QtWidgetsApplication1Class ui; };
|
1 2 3 4
| void QtWidgetsApplication1::updateProgress(int nNum) { ui.progressBar->setValue(nNum); }
|
建立信号与槽的联系
在主线程中建立信号与槽的联系
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| void QtWidgetsApplication1::on_pushButton_clicked() { QThread* m_workThread = new QThread(); workThread* worker = new workThread(); worker->moveToThread(m_workThread);
connect(worker, &workThread::updateProgress, this, &QtWidgetsApplication1::updateProgress); connect(m_workThread, &QThread::started, worker, &workThread::start1); connect(worker, &workThread::workFinished, worker, &workThread::deleteLater); connect(worker, &workThread::workFinished, m_workThread, &QThread::quit); connect(m_workThread, &QThread::finished, m_workThread, &QThread::deleteLater); worker->m_bStart = true; m_workThread->start(); worker->m_bStart = false; }
|
发送信号
在子线程处理耗时(循环)任务时,不断发送信号,将数据传递给主线程用于更新进度条
1 2 3 4 5 6 7 8 9
| void workThread::doWork() { for (int i = 0; i < 1000000; i++) { qDebug() << i; emit updateProgress(i + 1); } emit workFinished(); }
|
初始化进度条的属性
1 2 3 4 5 6 7 8
| QtWidgetsApplication1::QtWidgetsApplication1(QWidget *parent) : QWidget(parent) { ui.setupUi(this); ui.progressBar->setRange(0, 100); ui.progressBar->setMinimum(0); ui.progressBar->setMaximum(1000000); }
|
结果展示
程序运行截图如下:
此时,程序在执行1000000次循环输出,可以实时更新处理进度
辅助知识
connect函数的五个参数表示的意义依次为:sender*
,signal
,receiver*
,slot
,connectionTpye
其中槽可以是receiver的成员函数,或者是任意可访问的静态函数。