利用多线程,但比之前更专业!子线程负责串口和图片文件的读写操作,主线程负责UI界面的更新!!!
main.cpp
#include "mywidget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyWidget w;
w.show();
return a.exec();
}
mywidget.h
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QThread>
//包含自定义类的头文件
#include "mythread.h"
namespace Ui {
class MyWidget;
}
class MyWidget : public QWidget
{
Q_OBJECT
public:
explicit MyWidget(QWidget *parent = 0);
~MyWidget();
void detectSerial();//探测系统可用的串口列表
void serialDisplay(QByteArray tmp);//显示串口数据(如何显示、显示什么自己定义)
//处理关闭窗口/应用程序的操作
//主要是为了结束子线程
void dealClose();
private slots:
//串口选择下拉框槽函数
void on_comboBox_SerialNum_currentIndexChanged(const QString &arg1);
private:
Ui::MyWidget *ui;
//7. 涉及到子线程的成员尽量声明成指针类型
//如果声明成对象,在主线程构造函数初始化的时候默认把它当做主线程对象
//从而产生跨线程调用对象的错误
MyThread *myT;//自定义对象指针--将要放入子线程
QThread *thread;//子线程--负责串口数据的读取
signals:
void initUart(QSerialPortInfo info);//发送给子线程的串口初始化信号
};
#endif // MYWIDGET_H
mywidget.cpp
#include "mywidget.h"
#include "ui_mywidget.h"
MyWidget::MyWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::MyWidget)
{
//对于子线程的东西(将被移入子线程的自定义对象以及线程对象),最好定义为指针
myT = new MyThread;//将被子线程处理的自定义对象不能在主线程初始化的时候指定父对象
thread = new QThread(this);//初始化子线程线程
myT->moveToThread(thread);//将自定义对象移交给子线程,从此子线程控制他的成员函数
//启动子线程,但是没有启动真正的子线程处理函数,
//只是让子线程对象开始监控移交给他的相关对象
thread->start();
//绑定/连接关闭应用程序窗口的信号和主线程的dealClose槽函数
connect(this, &MyWidget::destroyed, this, &MyWidget::dealClose);
ui->setupUi(this);//绘制界面
detectSerial();//探测当前系统可用的串口列表
}
//析构函数
MyWidget::~MyWidget()
{
delete ui;
}
void MyWidget::dealClose()
{
if(thread->isRunning() == false)
{
return;
}
//2.如果调用的是子线程的函数(对象已被放入子线程,其成员函数均在子线程)
//需要在子线程退出的之前调用
myT->setFlag(true);//更新子线程的isStop标志--结束子线程的处理函数
//3.退出子线程要显示的调用这两个函数,否则主线程退出但子线程还在运行
thread->quit();
//回收资源
thread->wait();
//4. 将要被放入子线程的对象在主线程初始化(构造)的时候不能指定父对象,且需要在子线程结束以后显示delete
delete myT;
}
void MyWidget::detectSerial()
{
//1. 绑定信号和曹的时候,如果带参数,在QT5中可以直接给出信号和槽函数名即可
//但是,如果所传递的参数类型是未注册(非本地默认识别的可传递类型)的,需要在绑定之前进行注册
qRegisterMetaType<QSerialPortInfo>("QSerialPortInfo");
//连接子线程的isDone信号到主线程的serialDisplay槽函数,显示串口接收到的数据
connect(myT,&MyThread::isDone,this,&MyWidget::serialDisplay);
//连接主线程的initUart信号到子线程的initSerial槽函数,开始串口初始化
connect(this,&MyWidget::initUart,myT,&MyThread::initSerial);
//获取可用串口列表
QList<QSerialPortInfo> infos = QSerialPortInfo::availablePorts();
if(infos.isEmpty())//系统无可用串口
{
ui->comboBox_SerialNum->addItem("无效");//在串口选择下拉框显示“无效”
return