您的位置:首页 > 产品设计 > UI/UE

Qt GUI程序中主线程与非主线程之间的通信

2015-12-04 09:45 537 查看
Qt应用程序exec后就会生成一个线程,这个线程就是主线程,在GUI程序中也称为GUI线程。主线程也是唯一允许创建QApplication或QCoreAppliation对象,比并且可以对创建的对象调用exec()的线程,从而进入事件循环。

在只有主线程即单线程的情况中,每一个事件的发生都需要进入事件循环进行等待,如有在某一步计算量比较大,则会一直占用CPU不放,导致其它操作无法完成,界面陷入冻结状态,例如像下面的情况:

在主界面中有两个按钮,其中一个按钮用于一个非常大的计算并在结束的显示结果,另外一个按钮用于显示文本“hello, world!”。代码如下:

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_calculationButton_clicked();

void on_displayButton_clicked();

private:
Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H


mainwindow.cpp:

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QString>

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}

MainWindow::~MainWindow()
{
delete ui;
}

void MainWindow::on_calculationButton_clicked()  //计算
{
int result = 0;
for(int i = 0; i < 2000000000; i++)
result += i;

ui->displayEdit->setText(QString::number(result));
}

void MainWindow::on_displayButton_clicked()  //单击显示文本
{
static int flag = 0;
if(flag == 0)
{
flag = 1;
ui->displayEdit->setText(tr("hello, world!"));
}
else
{
flag = 0;
ui->displayEdit->setText(tr("I Love You!"));
}
}


结果:



可以看到,在点击计算按钮之后,进入计算,界面被冻结住了,如果在点击窗口上的其它按钮,则无法反映。

对于这种超大计算量的操作,我们将其分离出去单独处理,处理好了在跟主界面反馈一个结果即可,像这种情况就需要为主线程另外开辟一个新的线程来处理计算,并且在计算结束的时候与主线程通信,反馈结果。反馈结果需要一个同步操作,而Qt中的signal/slot正好能够满足这个要求,于是,我们将计算操作放到另外一个线程中进行,然后将计算结果通过一个signal传递到主线程中的一个slot,从而实现了与主线程之间的通信。代码修改如下:

mainwindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

class Thread;

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();

private slots:
void on_calculationButton_clicked();  //计算按钮
void on_displayButton_clicked();  //显式按钮
void displayResult(int);

private:
Ui::MainWindow *ui;

Thread *thread;
};

#endif // MAINWINDOW_H


thread.h:

#ifndef THREAD_H
#define THREAD_H

#include <QThread>

class Thread : public QThread{
Q_OBJECT

public:
Thread();  //构造函数

signals:
void returnResult(int);

protected:
void run();
};

#endif // THREAD_H


mainwindow.cpp:

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QString>
#include "thread.h"

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);

thread = new Thread();
connect(thread, SIGNAL(returnResult(int)), this, SLOT(displayResult(int)));
}

MainWindow::~MainWindow()
{
delete ui;
}

void MainWindow::on_calculationButton_clicked()  //计算
{
thread->start();
}

void MainWindow::on_displayButton_clicked()  //单击显示文本
{
static int flag = 0;
if(flag == 0)
{
flag = 1;
ui->displayEdit->setText(tr("hello, world!"));
}
else
{
flag = 0;
ui->displayEdit->setText(tr("I Love You!"));
}
}

void MainWindow::displayResult(int result)
{
ui->displayEdit->setText(QString::number(result));
}


thread.cpp:

#include "thread.h"

Thread::Thread()
{
//
}

void Thread::run()
{
int result = 0;
for(int i = 0; i < 2000000000; i++)
result += i;

emit returnResult(result);  //将结果放在信号中
}


运行结果如下:



可以看到,在点击计算按钮之后,在点击显示文本按钮仍然可以得到结果。在另外一个线程中计算结束后,便会改变主线程中的显示结果。



总结:当主线程需要另外一个线程提供服务,需要另外一个线程中的计算结果来修改主线程中的某个控件状态或内容。我们可以为这些超级复杂的任务开辟一个新的线程,在这个线程中执行任务,然后将执行结果通过一个signal来传递给主线程,如果有输出则可以通过signal的参数传递,如果仅仅只需要一个信号则不需要参数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: