Qt 创建线程的两种方法

方法一:Qt4.7及以前版本

1.创建一个类从QThread类派生
1)在项目中新建一个基于QObiect的c++ class类文件(例如MyThread ),生成MyThread .h和MyThread .cpp两个文件
2)在头文件MyThread .h中修改两处,a)将包含的头文件#include< QObiect >替换成#include < QThread >,b)将继承的基类class MyThread : public QObiect 修改为class MyThread : public QThread
3)在MyThread .cpp中,将MyThread::MyThread(QObject *parent) : QObject (parent)修改为MyThread::MyThread(QObject *parent) : QThread(parent)

2.在子线程类workThread.cpp中重写run函数,将处理操作写入该函数中,例如:

void MyThread::run()
{
    //复杂的数据处理,需要耗时5秒,用sleep(5)代替
    sleep(5);
    emit isDone();//数据处理结束信号
}

3.在主线程mywidget.cpp中创建子线程 对象,启动子线程,调用start()函数,
例如

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

    //线程函数处理完毕,发送isDone信号,窗口执行dealDone函数关闭定时器
     connect(thread,&MyThread::isDone,this,&MyWidget::dealDone);

    //当按下窗口右上角“X”关闭线程函数
     connect(this,&MyWidget::destroyed,this,&MyWidget::stopThread);
}

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

 void MyWidget::dealTimeout()
{
     static int i=0;
     i++;
     ui->lcdNumber->display(i);
}
 
 //按下启动按钮
void MyWidget::on_pushButton_clicked()
{
    //如果定时器没有工作
    if(mytimer->isActive()==false)
    {
        //定时器时间间隔为100毫秒(每隔100ms启动一次定时器)
        mytimer->start(100);
    }
    //启动线程,处理数据
    thread->start();
}

void MyWidget::dealDone()
{
     qDebug()<<"over";
     mytimer->stop();//关闭定时器
}
 
void MyWidget::stopThread()
{
    //停止线程
    thread->quit();
    //等待线程处理完手头工作
    thread->wait();
}

方法二:Qt4.8及以后版本

1.在项目中新建一个基于QObiect的c++ class类文件(例如MyThread ),生成MyThread .h和MyThread .cpp

2.在主线程函数中mywidget.cpp创建一个QThread类对象

   //自定义线程动态分配空间,不能指定父对象
    myT =new MyThread;

3.在主线程函数中mywidget.cpp中创建一个线程模板类对象

   //创建子线程,分配内存空间同时指定父对象
    thread =new QThread(this);

4.将线程模板类对象myT 移动到子线程thread中

   //把自定义的线程加入到子线程中
    myT->moveToThread(thread);

5.在主线程函数mywidget.cpp中启动子线程

   //启动线程,但是没有启动线程处理函数
    thread->start();//间接调用run函数

6.通过信号槽方式,执行线程模板类中的线程处理函数myTimeOut
以下过程如下:
1)ui界面上按下start按钮,自动触发槽信号函数void on_buttonStart_clicked();启动线程:thread->start(),并发送线程启动信号emit startThread()

//start按钮按下函数
void MyWidget::on_buttonStart_clicked()
{
    //如果thread线程函数已经处于运行状态,跳出该函数,不执行以下部分
    if(thread->isRunning()==true)
    {
        return;
    }

    //启动线程,但是没有启动线程处理函数
    thread->start();//间接调用run函数
    myT->setFlag(false);

    //不能直接调用线程处理函数
    //直接调用,导致线程处理函数和主线程是在同一个线程
    //只能通过信号和槽的方式调用
    // myT->myTimeOut();

    //窗口发送信号,启动线程处理函数
    emit startThread();
}

2)窗口发送startThread启动线程信号后,自定义线程函数myT执行myTimeOut函数

//窗口发送startThread启动线程信号,自定义线程函数myT执行myTimeOut函数
    connect(this,&MyWidget::startThread,myT,&MyThread::myTimeOut);

3)在myTimeOut函数中设置一个sleep()一秒后发送mySignal信号,相当于一个定时器

//自定义子线程函数
void MyThread::myTimeOut()
{
    //当isStop==ture的时候退出循环
    while(isStop==false)
    {
        //每隔1秒发送一个信号
        QThread::sleep(1);
        emit mySignal();

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

        if(true==isStop)
        {
            break;
        }
    }
}

4)自定义线程函数myT发送mySignal信号,窗口接收后,执行dealSignal函数,

//自定义线程函数myT发送mySignal信号,窗口接收后,执行dealSignal函数
    connect(myT,&MyThread::mySignal,this,&MyWidget::dealSignal);
    qDebug()<<"主线程号:"<<QThread::currentThread();

5)dealSignal实现在LCD上实时显示i值

//窗口信号处理函数,在LCD上显示i值
void MyWidget::dealSignal()
{
    static int i=0;
    i++;
    ui->lcdNumber->display(i);
}

6)直到等待按下ui界面上的stop或退出程序按钮
按下stop按钮后:退出子程序

//stop按钮按下函数
void MyWidget::on_buttonStop_clicked()
{
    //如果thread线程函数已经处于停止运行状态,跳出该函数,不执行以下部分
    if(thread->isRunning()==false)
    {
        return;
    }

    //将标志值设置为true,此时退出自定义线程函数myT
    myT->setFlag(true);

    //子线程函数退出
    thread->quit();
    thread->wait();
}

按下退出按钮后:触发dealClose函数,退出子程序,关闭窗口,释放内存

//关闭窗口时,窗口执行dealClose
    connect(this,&MyWidget::destroyed,this,&MyWidget::dealClose);
void MyWidget::dealClose()
{
    on_buttonStop_clicked();
    delete myT;//关闭窗口时释放myT内存
}

项目文件和简单界面图如下:

在这里插入图片描述在这里插入图片描述
多线程使用注意事项:

1.自定义线程模板对象myT,构造的时候不能指定父对象

2.在整个程序中,函数MyWidget(执行ui界面绘制与更新)相当于主线程,而mythread,相当于自定义的子线程,不能处理UI窗口(ui相关的类),只能处理一些数据相关的操作,不能涉及窗口

发布了9 篇原创文章 · 获赞 2 · 访问量 4100

猜你喜欢

转载自blog.csdn.net/qq_27085429/article/details/86480953