Qt Creator (8)————多线程

目录

通常情况下,应用程序都是在一个线程中执行操作,但当调用一个耗时操作时,用户界面常常会冻结,而使用多线程可以解决这一问题。多线程有以下几个优势:

     


  • 线程介绍:

在Qt中使用QThread 来管理线程。下面来看一个简单的例子:

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

void MyWidget::dealTimeout()
{
    static int i=0;
    i++;

    //设置lcd的值
    ui->lcdNumber->display(i);
}

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

void MyWidget::on_pushButton_clicked()
{
    //如果定时器没有工作
    if(myTimer->isActive()==false)
    {
        myTimer->start(100);
    }

    //非常复杂的数据处理,耗时较长
    QThread::sleep(5);

    //处理完数据后,关闭定时器
    //myTimer->stop();
    qDebug() << "over";
}

主界面有一个用于显示时间的 LCD 数字面板还有一个用于启动任务的按钮。程序的目的是用户点击按钮,开始一个非常耗时的运算(程序中我们以一个 2000000000 次的循环来替代这个非常耗时的工作,在真实的程序中,这可能是一个网络访问,可能是需要复制一个很大的文件或者其它任务),同时 LCD 开始显示逝去的毫秒数。毫秒数通过一个计时器QTimer进行更新。计算完成后,计时器停止。这是一个很简单的应用,也看不出有任何问题。但是当我们开始运行程序时,问题就来了:点击按钮之后,程序界面直接停止响应,直到循环结束才开始重新更新。

Qt Creator (8)————多线程_第1张图片                   Qt Creator (8)————多线程_第2张图片

但我们注释掉 myTimer->stop(); 语句时,LED显示会在5s后出现

Qt Creator (8)————多线程_第3张图片                  Qt Creator (8)————多线程_第4张图片

 

  • 多线程的使用:

Qt Creator (8)————多线程_第5张图片

让线程睡眠5s:

//mythread.cpp

MyThread::MyThread(QObject *parent) : QThread(parent)
{

}

void MyThread::run()
{
    //非常复杂的数据处理,耗时较长
    sleep(5);
    emit isDone();
}
//mywidget.cpp
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=0;
    i++;

    //设置lcd的值
    ui->lcdNumber->display(i);
}

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

void MyWidget::on_pushButton_clicked()
{
    //如果定时器没有工作
    if(myTimer->isActive()==false)
    {
        myTimer->start(100);
    }

//    //非常复杂的数据处理,耗时较长
//    QThread::sleep(5);

//    //处理完数据后,关闭定时器
//    //myTimer->stop();
//    qDebug() << "over";

    //启动线程,处理数据
    thread->start();

}

结果如下:

Qt Creator (8)————多线程_第6张图片               Qt Creator (8)————多线程_第7张图片

 

线程到5s时就会停止

 

Qt Creator (8)————多线程_第8张图片

主线程和子线程互不占用和阻塞,可以随时开始和暂停,并且退出窗口时不会占内存

mythread.cpp

MyThread::MyThread(QObject *parent) : QObject(parent)
{
    isStop=false;
}

void MyThread::myTimeout()
{
    while(!isStop)
    {
        QThread::sleep(1);
        emit mySignal();
        //QMessageBox::about(NULL);

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

        if(isStop)
        {
            break;
        }
    }
}

void MyThread::setFlag(bool flag)
{
    isStop=flag;
}
mywidget.cpp

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

    //线程处理函数内部,不允许操作图形界面

}

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

void MyWidget::dealClose()
{
    on_buttonStop_clicked();
}

void MyWidget::dealSignal()
{
    static int i=0;
    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();
}

结果如下:

Qt Creator (8)————多线程_第9张图片              Qt Creator (8)————多线程_第10张图片

 

总结:

* 队列连接:槽函数在接受者所在线程执行

* 直接连接:槽函数在发送者所在线程执行

* 自动连接:二者不在同一线程时,等同于队列连接

 

  • 使用线程绘图:

在窗口中有一个按钮,当点击按钮之后,在线程中随机

绘制一张图片,然后将给绘制好的图片显示到当前窗口中。

Qt Creator (8)————多线程_第11张图片

//widget.cpp

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

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(50,50,image);
}
//mythread.cpp

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

    //把画刷交给画家
    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);
}

结果如下:

Qt Creator (8)————多线程_第12张图片

Qt Creator (8)————多线程_第13张图片    Qt Creator (8)————多线程_第14张图片

按下按钮,可以随机生成一个图片

你可能感兴趣的:(Qt,Creator)