之前在写相机的一个项目,需要按照帧率实现多线程采集,我们用qt来实现下,首先第一种方式,直接继承OThread来创建自定义的线程类,我们用QTcreator来创建一个项目,这个项目我们准备实现一个计数的效果,窗口实时显示,我们先在ui中拖拽设置下界面,如图所示,这是我设置的界面首先设置一个终点数,比如1000,点击开始然后界面显示从0-1000,如果这个不用子线程,直接在主线程中实现毫无意外程序会崩溃无响应,要么无法实时看到数字显示的效果,要么直接被迫关闭。在qt中主线程也叫gui线程,包括对一些页面用户事件进行处理,由qt自带的,因此我们随便创建一个qt项目,都有主线程,可以很方便地让用户实现界面操作和管理。而对于一些耗时的需要计算的任务,用主线程处理就会导致阻塞了,造成页面无法响应直至强制退出的结果,因此对于一些耗时操作,需要子线程来实现。简单地来说,子线程处理逻辑事务,主线程处理界面ui事务。像对于我们的这个功能,界面实时显示数字这个操作是交给主线程来实现的,而里面的一些逻辑事务,像实现从0-1000循环的操作是通过子线程来实现的,那么这就很好办了,先子线程实现,并将实现的结果传给主线程显示即可。接下来我们通过继承QThread来实现多线程,新建文件,如图所示由于我们要继承QThread的,而这个没有这个选项,我们选择QObject即可,后面我么在代码中手动更改回来即可。设置类名Mythread,记得大写,然后点击下一步,下一步即可,然后目录就多了mythread.h,mythread.cpp文件。然后在mythread.h中更改,代码如下
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
class Mythread : public QThread
{
Q_OBJECT
public:
explicit Mythread(QObject *parent = nullptr);
signals:
public slots:
};
#endif // MYTHREAD_H
mythread.cpp代码如下
#include "mythread.h"
Mythread::Mythread(QObject *parent) : QThread(parent)
{
}
由于线程的逻辑都通过run方法实现执行的,我们得实现run方法(重写),完整代码,mythread.h文件代码
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
class Mythread : public QThread
{
Q_OBJECT
public:
explicit Mythread(QObject *parent = nullptr);
virtual void run() override;
signals:
void send(int num);
public slots:
};
#endif // MYTHREAD_H
mythread.cpp文件代码
#include "mythread.h"
#include<QDebug>
Mythread::Mythread(QObject *parent) : QThread(parent)
{
}
void Mythread::run()
{
for(int i=0;i<1000000;i++)
{
emit send(i);
qDebug()<<i;
}
}
widget.h代码
#ifndef WIDGET_H
#define WIDGET_H
#include<mythread.h>
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
public slots:
void showMsg(int num);
//点击开始启动线程
void on_btn_start_clicked();
private:
Ui::Widget *ui;
Mythread *mythread = nullptr;
};
#endif // WIDGET_H
widget.cpp代码
#include "widget.h"
#include "ui_widget.h"
#include<mythread.h>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
mythread = new Mythread();
//接收子线程传来的数据
connect(mythread,SIGNAL(send(int)),this,SLOT(showMsg(int)));
}
Widget::~Widget()
{
delete ui;
}
void Widget::showMsg(int num)
{
ui->label_show->setText(QString::number(num));
}
void Widget::on_btn_start_clicked()
{
mythread->start();
}
完美实现,整个过程很容易,通过信号和槽来启动子线程,子线程传来数据到主线程显示即可,这是直接继承QThread实现的多线程,接下来我们换另一种方法,即间接继承QThread实现多线程,这个更加灵活。上面的我们直接继承QThread的是将QObject改成了QThread,而间接继承的则不用这样更改了,mythread.h的完整代码如下所示
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QObject>
class Mythread : public QObject
{
Q_OBJECT
public:
explicit Mythread(QObject *parent = nullptr);
signals:
void send(int num);
public slots:
void working();
};
#endif // MYTHREAD_H
mythread.cpp的完整代码如下所示
#include "mythread.h"
#include<QDebug>
Mythread::Mythread(QObject *parent) : QObject(parent)
{
}
void Mythread::working()
{
for(int i=0;i<1000000;i++)
{
emit send(i);
qDebug()<<i;
}
}
widget.h的完整代码如下所示
#ifndef WIDGET_H
#define WIDGET_H
#include<mythread.h>
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
public slots:
void showMsg(int num);
//点击开始启动线程
void on_btn_start_clicked();
private:
Ui::Widget *ui;
Mythread *mythread = nullptr;
QThread *t = nullptr;
signals:
void begin();
};
#endif // WIDGET_H
widget.cpp的完整代码如下所示
#include "widget.h"
#include "ui_widget.h"
#include<mythread.h>
#include<QThread>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
mythread = new Mythread();
t = new QThread();
mythread->moveToThread(t);
connect(this,&Widget::begin,mythread,&Mythread::working);
//接收子线程传来的数据
connect(mythread,SIGNAL(send(int)),this,SLOT(showMsg(int)));
}
Widget::~Widget()
{
delete ui;
}
void Widget::showMsg(int num)
{
ui->label_show->setText(QString::number(num));
}
void Widget::on_btn_start_clicked()
{
emit begin();
t->start();
}
实现效果一样,完美,现在来说下二者的不同,间接继承QThread的方法子线程实现逻辑的函数名可以自定义,而直接继承QThread的方法固定run,并且只能重写,间接继承QThread的方法线程函数可以带有参数,十分方便的可以通过主线程传递,而直接继承的线程run函数不能带有参数,主线程要想给子线程传递参数必须通过内部成员变量进行传递,有点麻烦,无法灵活使用。
点击此处登录后即可评论