/*******************************************************************************************/

一、为什么需要使用线程

图形界面中一旦使用了线程休眠,图形界面就不会刷新(不会动),呈现卡住无响应的状态。

这是由于图形界面中是单线程的

所以  很复杂的数据处理 耗时长的,就需要创建线程。

QThread 线程类,

qt中的线程睡眠函数:QThread::sleep();

void MyWidget::on_pushButton_clicked()

{

//如果定时器没有工作

if(myTimer->isActive() == false)

{

myTimer->start(100);

}

//很复杂的数据处理

//需要耗时5s

sleep(5);//图形界面中一旦使用了线程休眠,图形界面就不会刷新(不会动),呈现卡住无响应的状态。

//也就是说由于睡眠,导致前面启动了的定时器都不工作

myTimer->stop();//过了5s后图形界面才会有响应。但是

//此时是停了定时器,前面是睡眠 定时器也不工作,所以呈现出一直定时器一直不工作的状态

}

/*******************************************************************************************/

二、线程

1.Qt4.7以前 线程的使用方法:

1).自定义一个类,继承于QThread

class MyThread : public QThread

{

public:

void run();//只有这个是线程处理函数(和主线程不在同一个线程),虚函数。

}

2).使用自定义的类创建对象,并开启线程

MyThread myThread;

//启动线程

//注意不能直接调用run函数,否则还是在主线程里面运行,而不是在新线程里面

myThread.start();//间接调用run

3).返回处理结果,告诉处理完

可以在类中定义一个信号,然后在需要(处理好后)的时候发送这个信号,来告诉其他线程。

具体见图《线程1》

2.实现:

在项目中添加一个继承QThread的类,添加的时候注意由于这个不是控件,所以下拉框选择QObject,然后

再在文件中把基类改为QThread

class MyThread : public QThread

{

Q_OBJECT

public:

explicit MyThread(QObject *parent = 0);

protected:

//QThread的虚函数

//线程处理函数

//不能直接调用,通过start()间接调用

void run();

signals:

void isDone();

public slots:

};

void MyThread::run()

{

//很复杂的数据处理

//需要耗时5s

sleep(5);

emit isDone();

}

//分配空间

thread = new MyThread(this);

//处理线程中的信号,最好用这种传统的方式

connect(thread, &MyThread::isDone, this, &MyWidget::dealDone);

//当按窗口右上角x时,窗口触发destroyed(),否则关了窗口线程还会运行

connect(this, &MyWidget::destroyed, this, &MyWidget::stopThread);

void MyWidget::dealDone()

{

qDebug() << "it is over";

myTimer->stop(); //关闭定时器

}

void MyWidget::on_pushButton_clicked()

{

//如果定时器没有工作

if(myTimer->isActive() == false)

{

myTimer->start(100);

}

//启动线程,处理数据

thread->start();

}

void MyWidget::stopThread()

{

//停止线程,不是立马关闭,释放线程占用的内存,线程号等资源。和下面配合使用

thread->quit();//类似linux中,pthread_exit()

//等待线程处理完手头动作

thread->wait();//类似linux中,pthread_join , pthread_detach,

//terminate 强制结束,很暴力,往往会导致内存问题。所以一般不用

}

上述代码具体见《QThread》

 #ifndef MYWIDGET_H
#define MYWIDGET_H #include <QWidget>
#include <QTimer> //定时器头文件
#include "mythread.h" //线程头文件 namespace Ui {
class MyWidget;
} class MyWidget : public QWidget
{
Q_OBJECT public:
explicit MyWidget(QWidget *parent = );
~MyWidget(); void dealTimeout(); //定时器槽函数
void dealDone(); //线程结束槽函数
void stopThread(); //停止线程槽函数 private slots:
void on_pushButton_clicked(); private:
Ui::MyWidget *ui; QTimer *myTimer; //声明变量
MyThread *thread; //线程对象
}; #endif // MYWIDGET_H

mywidget.h

 #include "mywidget.h"
#include "ui_mywidget.h"
#include <QThread>
#include <QDebug> MyWidget::MyWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::MyWidget)
{
ui->setupUi(this); myTimer = new QTimer(this); //只要定时器启动,自动触发timeout()
connect(myTimer, &QTimer::timeout, this, &MyWidget::dealTimeout); //分配空间
thread = new MyThread(this); connect(thread, &MyThread::isDone, this, &MyWidget::dealDone); //当按窗口右上角x时,窗口触发destroyed()
connect(this, &MyWidget::destroyed, this, &MyWidget::stopThread); } void MyWidget::stopThread()
{
//停止线程
thread->quit();
//等待线程处理完手头动作
thread->wait();
} void MyWidget::dealDone()
{
qDebug() << "it is over";
myTimer->stop(); //关闭定时器
} void MyWidget::dealTimeout()
{
static int i = ;
i++;
//设置lcd的值
ui->lcdNumber->display(i);
} MyWidget::~MyWidget()
{
delete ui;
} void MyWidget::on_pushButton_clicked()
{
//如果定时器没有工作
if(myTimer->isActive() == false)
{
myTimer->start();
} //启动线程,处理数据
thread->start(); }

mywidget.cpp

 #ifndef MYTHREAD_H
#define MYTHREAD_H #include <QThread> class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = ); protected:
//QThread的虚函数
//线程处理函数
//不能直接调用,通过start()间接调用
void run(); signals:
void isDone(); public slots:
}; #endif // MYTHREAD_H

mythread.h

 #include "mythread.h"

 MyThread::MyThread(QObject *parent) : QThread(parent)
{ } void MyThread::run()
{
//很复杂的数据处理
//需要耗时5s
sleep(); emit isDone();
}

mythread.cpp

3.Qt4.7以后 线程的使用方法:

1).定义:

(1).设定一个类,继承与QObject

(2).类中设置一个线程函数(只有一个是线程函数,函数名可以任意)

class MyThread : public QObject

{

public:

void fun();//

}

2).使用:

(1).创建自定义线程对象(不能指定父对象),

否则后续就无法加入到QThread线程对象,因为指定后是已经给了窗口了就不能放到线程的地方了

或者说已经有父对象的则不能再移动了(不能移动到别的父对象)

myThread=new MyThread;

(2).创建QThread线程对象

QThread *thread = new QThread(this)

(3).把自定义线程类,加入到QThread线程对象,  关联起来

myThread->moveToThread(thread);

(4).启动线程对象的线程,

thread.start();//只是把线程开启了,并没有启动线程处理函数(线程是启动了,但是线程函数没有启动)

(5).线程处理函数(自定义线程函数)的启动,必须通过signal-slot 信号和槽的方式(不能直接调用这个函数):

主线程发送信号,并且信号的处理函数指定为线程处理函数,这样线程处理函数才启动了

(定义信号与槽必须要有Q_OBJECT宏)

connect(this, &MyWidget::startThread, myT, &MyThread::myTimeout);

(6).线程退出,直接退出是不行的,因为线程处理函数中的while(1)这样退出不了

//当按窗口右上角x时,窗口触发destroyed(),如果此时不关闭线程,则关了窗口线程还会运行

connect(this, &MyWidget::destroyed, this, &MyWidget::dealClose);//不像linux中进程关了则线程都关了,这里线程还会运行

注意使用前面:

thread->quit();//等待线程处理完,但是线程是死循环一致处理不完,所以线程无法退出

thread->wait();

这样线程不退出,必须先让线程处理函数退出循环,通过标志位的方法:

myT->setFlag(true);//设置退出标记,则循环条件不满足,则线程处理函数会退出

thread->quit();

thread->wait()

3).返回处理结果,

可以在类中定义一个信号,信号可以是带参数的,参数可以是处理后的数据

然后在需要(处理好后)的时候发送这个信号,来告诉其他线程。

具体见图《线程2》

4.实现:

void MyThread::myTimeout()

{

while( !isStop )

{

QThread::sleep(1);

emit mySignal();

//QMessageBox::aboutQt(NULL);

qDebug() << "子线程号:" << QThread::currentThread();

if(isStop)

{

break;

}

}

}

void MyWidget::on_buttonStart_clicked()

{

if(thread->isRunning() == true)

{

return;

}

//启动线程,但是没有启动线程处理函数

thread->start();

myT->setFlag(false);

//不能直接调用线程处理函数,

//直接调用,导致,线程处理函数和主线程是在同一个线程

//myT->myTimeout();

//只能通过 signal - slot 方式调用

emit startThread();

}

void MyWidget::on_buttonStop_clicked()

{

if(thread->isRunning() == false)

{

return;

}

myT->setFlag(true);

thread->quit();

thread->wait();

}

5.注意:

1).线程处理函数内部,不允许操作图形界面,也不允许创建图形界面,否则程序会奔溃。

线程处理函数内部一般是纯数据处理

2).connect()第五个参数的作用,第五个参数多线程时才有意义

connect()第五个参数表示的是连接方式,主要有三种:自动连接,队列连接,直接连接

默认的时候,用的是自动连接,自动连接时:

如果是多线程,默认使用队列连接 (通过(接收的)类来判断是否是子线程的)

如果是单线程, 默认使用直接连接方式

队列连接含义: 槽函数所在的线程和接收者一样

connect(this, &MyWidget::startThread, myT, &MyThread::myTimeout);

//槽函数所在的线程和myT一样,即在子线程中

直接连接含义:槽函数所在线程和发送者一样

connect(this, &MyWidget::startThread, myT, &MyThread::myTimeout,Qt::DirectConnection);

//槽函数所在的线程和this一样,即在主线程中,无法实现多任务

这就是为啥,启动线程处理函数使用connect的原因,默认是队列方式(多线程下)。

一般用默认就够了

上述代码具体见《ThreadPro》

 #ifndef MYWIDGET_H
#define MYWIDGET_H #include <QWidget>
#include "mythread.h"
#include <QThread> namespace Ui {
class MyWidget;
} class MyWidget : public QWidget
{
Q_OBJECT public:
explicit MyWidget(QWidget *parent = );
~MyWidget(); void dealSignal();
void dealClose(); signals:
void startThread(); //启动子线程的信号 private slots:
void on_buttonStart_clicked(); void on_buttonStop_clicked(); private:
Ui::MyWidget *ui;
MyThread *myT;
QThread *thread; }; #endif // MYWIDGET_H

mywidget.h

 #include "mywidget.h"
#include "ui_mywidget.h"
#include <QDebug> MyWidget::MyWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::MyWidget)
{
ui->setupUi(this); //动态分配空间,不能指定父对象
myT = new MyThread; //创建子线程
thread = new QThread(this); //把自定义线程加入到子线程中
myT->moveToThread(thread); connect(myT, &MyThread::mySignal, this, &MyWidget::dealSignal); qDebug() << "主线程号:" << QThread::currentThread(); connect(this, &MyWidget::startThread, myT, &MyThread::myTimeout); connect(this, &MyWidget::destroyed, this, &MyWidget::dealClose); //线程处理函数内部,不允许操作图形界面 //connect()第五个参数的作用,连接方式:默认,队列,直接
//多线程时才有意义
//默认的时候
//如果是多线程,默认使用队列
//如果是单线程, 默认使用直接方式
//队列: 槽函数所在的线程和接收者一样
//直接:槽函数所在线程和发送者一样 } MyWidget::~MyWidget()
{
delete ui;
} void MyWidget::dealClose()
{
on_buttonStop_clicked();
delete myT;
} void MyWidget::dealSignal()
{
static int i = ;
i++;
ui->lcdNumber->display(i);
} void MyWidget::on_buttonStart_clicked()
{ if(thread->isRunning() == true)
{
return;
} //启动线程,但是没有启动线程处理函数
thread->start();
myT->setFlag(false); //不能直接调用线程处理函数,
//直接调用,导致,线程处理函数和主线程是在同一个线程
//myT->myTimeout(); //只能通过 signal - slot 方式调用
emit startThread(); } void MyWidget::on_buttonStop_clicked()
{
if(thread->isRunning() == false)
{
return;
} myT->setFlag(true);
thread->quit();
thread->wait();
}

mywidget.cpp

 #ifndef MYTHREAD_H
#define MYTHREAD_H #include <QObject> class MyThread : public QObject
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = ); //线程处理函数
void myTimeout(); void setFlag(bool flag = true); signals:
void mySignal(); public slots: private:
bool isStop;
}; #endif // MYTHREAD_H

mythread.h

 #include "mythread.h"
#include <QThread>
#include <QDebug>
#include <QMessageBox> MyThread::MyThread(QObject *parent) : QObject(parent)
{
isStop = false;
} void MyThread::myTimeout()
{
while( !isStop )
{ QThread::sleep();
emit mySignal();
//QMessageBox::aboutQt(NULL); qDebug() << "子线程号:" << QThread::currentThread(); if(isStop)
{
break;
}
}
} void MyThread::setFlag(bool flag)
{
isStop = flag;
}

mythread.cpp

两种使用线程的方法,新方式是推荐的,但是老方式更好用。

/*******************************************************************************************/

三、线程画图

线程中可以绘图,可以使用绘图设备QImage

绘画完毕后可以把绘图结果即绘图设备,通过带参数(即绘图设备)的信号发送给主窗口

当绘图很复杂时,当然是放在线程中最合适。

void MyThread::drawImage()

{

//定义QImage绘图设备

QImage image(500, 500, QImage::Format_ARGB32);

//定义画家,指定绘图设备

QPainter p(&image);

//定义画笔对象

QPen pen;

pen.setWidth(5); //设置宽度

//把画笔交给画家

p.setPen(pen);

//定义画刷

QBrush brush;

brush.setStyle(Qt::SolidPattern); //设置样式

brush.setColor(Qt::red); //设置颜色

//把画刷交给画家

p.setBrush(brush);

//定义5个点

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

}

上述代码具体见《ThreadIamge》

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

widget.h

 #include "widget.h"
#include "ui_widget.h"
#include <QPainter>
#include <QThread> 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(); //线程处理函数,必须通过signal - slot 调用
connect(ui->pushButton, &QPushButton::pressed, myT, &MyThread::drawImage);
connect(myT, &MyThread::updateImage, this, &Widget::getImage); connect(this, &Widget::destroyed, this, &Widget::dealClose); } Widget::~Widget()
{
delete ui;
} void Widget::dealClose()
{
//退出子线程
thread->quit();
//回收资源
thread->wait();
delete myT; } void Widget::getImage(QImage temp)
{
image = temp;
update(); //更新窗口,间接调用paintEvent()
} void Widget::paintEvent(QPaintEvent *)
{
QPainter p(this); //创建画家,指定绘图设备为窗口
p.drawImage(, , image);
}

widget.cpp

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

mythread.h

 #include "mythread.h"
#include <QPainter>
#include <QPen>
#include <QBrush>
#include <QImage> MyThread::MyThread(QObject *parent) : QObject(parent)
{ } void MyThread::drawImage()
{
//定义QImage绘图设备
QImage image(, , QImage::Format_ARGB32);
//定义画家,指定绘图设备
QPainter p(&image); //定义画笔对象
QPen pen;
pen.setWidth(); //设置宽度
//把画笔交给画家
p.setPen(pen); //定义画刷
QBrush brush;
brush.setStyle(Qt::SolidPattern); //设置样式
brush.setColor(Qt::red); //设置颜色
//把画刷交给画家
p.setBrush(brush); //定义5个点
QPoint a[] =
{
QPoint(qrand()%, qrand()%),
QPoint(qrand()%, qrand()%),
QPoint(qrand()%, qrand()%),
QPoint(qrand()%, qrand()%),
QPoint(qrand()%, qrand()%)
}; p.drawPolygon(a, ); //通过信号发送图片
emit updateImage(image); }

mythread.cpp

界面编程之QT的线程20180731的更多相关文章

  1. 界面编程之QT的Socket通信20180730

    /*******************************************************************************************/ 一.linu ...

  2. 界面编程之QT的数据库操作20180801

    /*******************************************************************************************/ 一.数据库连 ...

  3. 界面编程之QT绘图和绘图设备20180728

    /*******************************************************************************************/ 一.绘图 整 ...

  4. 界面编程之QT的事件20180727

    /*******************************************************************************************/ 一.事件 1 ...

  5. 界面编程之QT窗口系统20180726

    /*******************************************************************************************/ 一.坐标系统 ...

  6. 界面编程之QT的信号与槽20180725

    /*******************************************************************************************/ 一.指定父对 ...

  7. 界面编程之QT的基本介绍与使用20180722

    /*******************************************************************************************/ 一.qt介绍 ...

  8. 界面编程之QT的文件操作20180729

    /*******************************************************************************************/ 一.QT文件 ...

  9. QT核心编程之Qt线程 (c)

    QT核心编程之Qt线程是本节要介绍的内容,QT核心编程我们要分几个部分来介绍,想参考更多内容,请看末尾的编辑推荐进行详细阅读,先来看本篇内容. Qt对线程提供了支持,它引入了一些基本与平台无关的线程类 ...

随机推荐

  1. Getting Start chrome-extension demo

    写一个小小的chrome扩展demo~ 准备工作 了解一下插件chrome-extension: 在应用商店里的插件基本上都是以.crx为文件后缀,该文件其实就是一个压缩包,包括插件所需要的html. ...

  2. 20155330 《网络攻防》 Exp3 免杀原理与实践

    20155330 <网络攻防> Exp3 免杀原理与实践 基础问题回答 杀软是如何检测出恶意代码的? 基于特征码.先对流行代码特征的提取,然后进行程序的比对,如果也检测到相应的特征码的程序 ...

  3. 备忘:BLOCK CORRUPTION IN SYSTEM DATAFILE

    http://www.onlinedbasupport.com/2010/12/10/block-corruption-in-system-datafile/

  4. python 回溯法 子集树模板 系列 —— 12、选排问题

    问题 从n个元素中挑选m个元素进行排列,每个元素最多可重复r次.其中m∈[2,n],r∈[1,m]. 如:从4个元素中挑选3个元素进行排列,每个元素最多可重复r次. 分析 解x的长度是固定的,为m. ...

  5. GATT scan的流程

    BLE scan 在bluedroid的实现中,有两个接口:一个是discovery,一个是ble observe,这两者有什么区别呢? 这里追了一下代码发现,inquiry 是上层调用search ...

  6. 定制 input[type="radio"] 和 input[type="checkbox"] 样式

    表单中,经常会使用到单选按钮和复选框,但是,input[type="radio"] 和 input[type="checkbox"] 的默认样式在不同的浏览器或 ...

  7. Python基础知识(Basic knowledge)

    Python基础知识(Basic knowledge) 1.认识Python&基础环境搭建 2.Python基础(上) 3.Python基础(中) 4.Python基础(下) 5.Python ...

  8. 设计模式 笔记 迭代器模式 Iterator

    //---------------------------15/04/26---------------------------- //Iterator 迭代器模式----对象行为型模式 /* 1:意 ...

  9. Java+Netty、Vue+Element-UI实现的即时通信应用 leo-im

    之前工作接触了几个开源的IM产品,再加上曾经用Netty实现过几个服务,于是就有了用Netty实现一个IM的想法,于是用业余时间写了一个IM,和喜欢Netty的程序员们分享. 考虑到方便扩展,在服务端 ...

  10. Unity协程Coroutine使用总结和一些坑

    原文摘自 Unity协程Coroutine使用总结和一些坑 MonoBehavior关于协程提供了下面几个接口: 可以使用函数或者函数名字符串来启动一个协程,同时可以用函数,函数名字符串,和Corou ...