Qt GUI程序中主线程与非主线程之间的通信
2015-12-04 09:45
537 查看
Qt应用程序exec后就会生成一个线程,这个线程就是主线程,在GUI程序中也称为GUI线程。主线程也是唯一允许创建QApplication或QCoreAppliation对象,比并且可以对创建的对象调用exec()的线程,从而进入事件循环。
在只有主线程即单线程的情况中,每一个事件的发生都需要进入事件循环进行等待,如有在某一步计算量比较大,则会一直占用CPU不放,导致其它操作无法完成,界面陷入冻结状态,例如像下面的情况:
在主界面中有两个按钮,其中一个按钮用于一个非常大的计算并在结束的显示结果,另外一个按钮用于显示文本“hello, world!”。代码如下:
mainwindow.h:
mainwindow.cpp:
结果:
可以看到,在点击计算按钮之后,进入计算,界面被冻结住了,如果在点击窗口上的其它按钮,则无法反映。
对于这种超大计算量的操作,我们将其分离出去单独处理,处理好了在跟主界面反馈一个结果即可,像这种情况就需要为主线程另外开辟一个新的线程来处理计算,并且在计算结束的时候与主线程通信,反馈结果。反馈结果需要一个同步操作,而Qt中的signal/slot正好能够满足这个要求,于是,我们将计算操作放到另外一个线程中进行,然后将计算结果通过一个signal传递到主线程中的一个slot,从而实现了与主线程之间的通信。代码修改如下:
mainwindow.h:
thread.h:
mainwindow.cpp:
thread.cpp:
运行结果如下:
可以看到,在点击计算按钮之后,在点击显示文本按钮仍然可以得到结果。在另外一个线程中计算结束后,便会改变主线程中的显示结果。
总结:当主线程需要另外一个线程提供服务,需要另外一个线程中的计算结果来修改主线程中的某个控件状态或内容。我们可以为这些超级复杂的任务开辟一个新的线程,在这个线程中执行任务,然后将执行结果通过一个signal来传递给主线程,如果有输出则可以通过signal的参数传递,如果仅仅只需要一个信号则不需要参数。
在只有主线程即单线程的情况中,每一个事件的发生都需要进入事件循环进行等待,如有在某一步计算量比较大,则会一直占用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的参数传递,如果仅仅只需要一个信号则不需要参数。
相关文章推荐
- Tips:取消UICollectionView的隐式动画
- UEFI安全启动怎么关闭 关闭UEFI启动项的方法图解
- UEFI怎么用 UEFI安全启动设置添加方法步骤图解
- 《apue》读书笔记 停止更新
- SQL Report Builder 报表里面的常见问题分析
- uefi启动是什么意思 UEFI启动对比Bios启动优势在哪里
- 限制UITextField 输入字数
- 使用UItableview在iOS应用开发中实现好友列表功能
- UEFI引导系统
- BroadcastReceiver更新UI
- UITextField输入框 只能输入两位小数
- sql里的in对应linq的写法 及 IQueryable转化为Dictionary
- easyui 布局标题纵向排列
- sql里的in对应linq的写法 及 IQueryable转化为Dictionary
- UITextView根据内容适应大小
- UITextView
- Android Studio aapt.exe finished with non-zero exit value 1
- 修改UITextField的placeHoder字体颜色
- codeforces Queries about less or equal elements 二分
- Bluetooth Low Energy 嗅探