Qt是一个GUI框架,在GUI程序中,主线程也叫GUI线程,因为它是唯一被允许执行GUI相关操作的线程。对于一些耗时的操作,如果放在主线程中,就是出现界面无法响应的问题。

解决方法一:在处理耗时操作中频繁调用QApplication::processEvents()。这个函数告诉Qt去处理那些还没有被处理的各类事件,然后再把控制权返还给调用者。

QElapsedTimer et;
et.start();
while(et.elapsed()<300)
QCoreApplication::processEvents();

解决方法二:采用多线程,将需要处理的后台数据放入子线程,为了能够跨线程调用,一种方法是使用类似线程锁对线程进行保护,另外一种方法使用Qt的信号槽机制。Qt的信号槽机制采用connect函数进行连接,connect函数其实是有第五个参数的,但这个参数往往在多线程调用中才会用到:

connect(Sender,SIGNAL(signal),Receiver,SLOT(slot),Qt::DirectConnection);

第五个参数代表槽函数在哪个线程中执行 :
1)自动连接(AutoConnection),默认的连接方式,如果信号与槽,也就是发送者与接受者在同一线程,等同于直接连接;如果发送者与接受者处在不同线程,等同于队列连接。
2)直接连接(DirectConnection),当信号发射时,槽函数立即直接调用。无论槽函数所属对象在哪个线程,槽函数总在发送者所在线程执行,即槽函数和信号发送者在同一线程
3)队列连接(QueuedConnection),当控制权回到接受者所在线程的事件循环时,槽函数被调用。槽函数在接受者所在线程执行,即槽函数与信号接受者在同一线程
4)锁定队列连接(QueuedConnection)
Qt::BlockingQueuedConnection:槽函数的调用时机与Qt::QueuedConnection一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。
5)单一连接(QueuedConnection)
Qt::UniqueConnection:这个flag可以通过按位或(|)与以上四个结合在一起使用。当这个flag设置时,当某个信号和槽已经连接时,再进行重复的连接就会失败。也就是避免了重复连接

如果槽函数中有耗时操作,比如说while循环,主线程的信号子线程是不会响应的,除非使用直接连接(DirectConnection),connect(this, &Controller::kill, worker, &Worker::stopWork, Qt::DirectConnection);,此时,槽函数工作于主线程。

下面是一个简单的多线程例子: (Qt有两种多线程的方法,其中一种是继承QThread的run函数,另外一种是把一个继承于QObject的类转移到一个Thread里。 Qt4.8之前都是使用继承QThread的run这种方法,但是Qt4.8之后,Qt官方建议使用第二种方法。两种方法区别不大,用起来都比较方便,但继承QObject的方法更加灵活。

1、继承于QObject的线程

创建QWidget项目之后,在UI界面放入一个按钮,项目中添加自定义线程类mythread,继承于QObject;
上代码:
mythread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QImage>
#include <QObject> class MyThread : public QObject
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = 0);
~MyThread();
//线程处理函数
void drawImage(); signals:
void updateImage(QImage temp); public slots:
}; #endif // MYTHREAD_H

mythread.cpp

#include "mythread.h"
#include <QPainter>
#include <QImage>
MyThread::MyThread(QObject *parent) : QObject(parent)
{ } void MyThread::drawImage()
{//定义Image绘图设备,透明绘图背景
QImage image(500,500,QImage::Format_ARGB32);
//定义画家,指定绘图设备
QPainter p(&image);
//定义画笔对象
QPen pen;
//设置画笔宽度
pen.setWidth(1);
//把画笔交给画家
p.setPen(pen);
//定义画刷
QBrush brush;
brush.setStyle(Qt::SolidPattern);
brush.setColor(Qt::blue);
p.setBrush(brush);
//定义5个随机点,500*500为绘图背景大小,使点坐标不超出绘图背景
QPoint a[]=
{
QPoint(qrand()%500,qrand()%500),
QPoint(qrand()%500,qrand()%500),
QPoint(qrand()%500,qrand()%500),
QPoint(qrand()%500,qrand()%500),
QPoint(qrand()%500,qrand()%500),
};
//以给出的五个点画多边形
p.drawPolygon(a,5);
//通过信号发送图片
emit updateImage(image);
}
MyThread::~MyThread()
{ }

在Widget中加入自定义线程类的头文件,按下UI按钮之后子线程画图,画完之后将图片传给主线程,主线程获取图片之后更新绘图,代码如下:
widget.h

#ifndef WIDGET_H
#define WIDGET_H #include <QWidget>
#include "mythread.h"
#include <QThread> namespace Ui {
class Widget;
} class Widget : public QWidget
{
Q_OBJECT public:
explicit Widget(QWidget *parent = 0);
~Widget();
//重写绘图事件
void paintEvent(QPaintEvent *);
void getImage(QImage);
void dealClose(); private:
Ui::Widget *ui;
QImage image;
//自定义线程
MyThread *myT;
//子线程
QThread *thread;
}; #endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QPainter>
#include <QThread>
#include <QImage>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//自定义线程,不能指定父对象,否则无法传入线程
myT = new MyThread;
//创建子线程
thread = new QThread(this);
//把自定义线程类添加到子线程
myT->moveToThread(thread);
//启动子线程,不启动线程处理函数
thread->start();
//通过信号和槽机制调用线程处理函数
//按钮按下时,调用自定义线程画图函数
connect(ui->pushButton,&QPushButton::pressed,myT,&MyThread::drawImage);
//绘图完毕后发送updateImage信号,更新绘图
connect(myT,&MyThread::updateImage,this,&Widget::getImage);
//关闭窗口时调用关闭子线程的函数
connect(this,&Widget::destroyed,this,dealClose); } void Widget::dealClose()
{
//停止线程,调用之后并不立即实现
thread->quit();
//等待线程完成当前工作
thread->wait();
//析构线程对象
delete myT; }
void Widget::getImage(QImage temp)
{
image = temp;
//更新窗口,间接调用paintevent()
update(); }
void Widget::paintEvent(QPaintEvent *)
{
QPainter p(this);
p.drawImage(50,50,image); }
Widget::~Widget()
{
delete ui;
}

2、继承于QThread的线程

继承与QThread的线程使用也很简单,但需要注意的是,thread线程里面,只有run函数里的代码是运行在新线程的,其他代码仍然在主线程中运行。
头文件:

#ifndef NETTHERAD_H
#define NETTHERAD_H
#include <QThread> class NetTherad : public QThread
{
public:
NetTherad();
void run(); }; #endif // NETTHERAD_H

源文件:

#include "nettherad.h"
#include "network.h"
#include <QDateTime>
#include <QDebug>
NetTherad::NetTherad()
{
} void NetTherad::run()
{
while(1)
qDebug()<<"net set time"<<QDateTime::currentDateTime().toString("hh:mm:ss"); }

在主线程中包含子线程头文件后调用start函数即可启动子线程:

    NetTherad *netthreadt = new NetTherad;
netthreadt->start();

如何优雅的结束一个线程,是需要思考的问题,建议使用的方法是在每次循环之前进行一个BOOL值的判断,当BOOL值为假时,退出循环(当然,也可以使用terminate()粗暴的结束线程)。当run函数里面没有循环时,函数像普通函数一样,运行完一次即退出函数。
线程结束时会发出信号,此时我们可以通过信号槽来销毁线程:

 connect(thread,&QThread::finished
,thread,&QObject::deleteLater);//线程结束后调用deleteLater来销毁分配的内存

参考链接:https://blog.csdn.net/caoshangpa/article/details/52784860
参考链接:https://blog.csdn.net/czyt1988/article/details/64441443

QT 相关的更多相关文章

  1. QT 相关资源(书籍、论坛、博客等。。。)整理

     QT 相关资源(书籍.论坛.博客等...)整理... 中文名:<提问的智慧> 英文名:How To Ask Questions The Smart Way 中文链接1:http://ww ...

  2. qmake.exe是在Qt安装编译时生成的,里面内嵌了Qt相关的一些路径(最简单的方法是保持一样的安装路径,最方便的办法是设置qt.conf文件)

    在网上直接下载别人编译好的Qt库,为自己使用省了不少事.但往往也会遇到些问题,其中Qt version is not properly installed,please run make instal ...

  3. Qt相关问题

    1.  Qt编译中的error: cannot find -lGL和 error: collect2: error: ld returned 1 exit status 一般见于新安装的系统,马上就直 ...

  4. 【QT相关】对话框相关

    为行编辑器限制规则: QRegExp regExp("[A-Za-z][1-9][0-9]{0,2}"); lineEdit->setValidator(new QRegEx ...

  5. 【QT相关】Qt Widgets Module

    Qt Widgets Module:提供了一些列UI元素. 使用: //头文件包含 #include <QtWidgets> //链接模式,在.pro文件中添加行: QT += widge ...

  6. 【QT相关】类头文件解读、QT编辑模式、读取text文本

    Wizard产生的头文件类包含了必须的#include文件.构造函数.析构函数和UI对象: #include <QMainWindow> namespace Ui {class Notep ...

  7. 【QT相关】QT+opencv环境配置

    在qt msvc2010版软件中使用opencv2.4.9进行库函数配置.仅适用于windows下. INCLUDEPATH += $$PWD/../../../opencv/build/includ ...

  8. QT 相关书籍

    qt qucik 核心编程 个人觉得此书写得非常之好....这位作者的另外一本虽然没看过,估计也不错 https://bbs.csdn.net/topics/390942701?list=lz qt5 ...

  9. Qt相关博客总览

    一.Qt快速入门 Qt快速入门之一:开始学习Qt 与Qt Creator Qt快速入门之二:Qt Creator简介 Qt快速入门之三:Qt程序编译和源码详解 Qt对话框之一:标准对话框 二.Qt窗口 ...

随机推荐

  1. RF和GBDT的区别

    Random Forest ​采用bagging思想,即利用bootstrap抽样,得到若干个数据集,每个数据集都训练一颗树. 构建决策树时,每次分类节点时,并不是考虑全部特征,而是从特征候选集中选取 ...

  2. 敏捷软件开发:原则、模式与实践——第13章 写给C#程序员的UML概述

    第13章 写给C#程序员的UML概述 UML包含3类主要的图示.静态图(static diagram)描述了类.对象.数据结构以及它们之间的关系,藉此表现出了软件元素间那些不变的逻辑结构.动态图(dy ...

  3. CodeSmith Generator 6.5 自动生成后的源码分析

    1,NetTiers代码结构流程分析: 2,CodeSmithNetTiers使用实践总结 参看流程结构图和实体定义文件关系图,可以看出自动代码生成后,若是手工来调,还是很麻烦的.鉴于此,建议:1,若 ...

  4. jmeter -分布式性能测试部署

    ------------------运行环境:------------------------------------------------- 1. 安装java运行环境:要求jdk1.8(最好安装 ...

  5. jQuery,Table表头固定插件chromatable存在的问题及解决办法

    在最近的项目中需要将表格的表头固定,搜寻了大量的资料,发现chromatable插件还是比较方便的.但是当我在一个页面中多次使用 chromatable固定对个表格的表头时问题就出现了,首先说明系统的 ...

  6. getpost请求

    // GET请求与获取结果 /// </summary> public static string HttpGet(string Url, string postDataStr) { Ht ...

  7. redis详细说明

    # By default Redis does not run as a daemon. Use 'yes' if you need it.# Note that Redis will write a ...

  8. ORM概述及常用ORM框架

    一.ORM ORM(Object-relational mapping),即对象关系映射,是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术.也就是说,ORM是通过使用描述对象和数据库之间映 ...

  9. 南昌网络赛J. Distance on the tree 树链剖分+主席树

    Distance on the tree 题目链接 https://nanti.jisuanke.com/t/38229 Describe DSM(Data Structure Master) onc ...

  10. IO模型《六》IO模型比较分析

    IO模型比较分析 到目前为止,已经将四个IO Model都介绍完了.现在回过头来回答最初的那几个问题:blocking和non-blocking的区别在哪,synchronous IO和asynchr ...