QT5串口上位机——从零开始教你写03
- 简单串口编写
- 3.线程类对象的添加和UI界面的参数设置
- 添加任务类对象和线程类对象
- 初始化ui界面参数
- 利用QSerialPortInfo得到串口号
简单串口编写
3.线程类对象的添加和UI界面的参数设置
添加任务类对象和线程类对象
打开工程,选择mainwidget.h,添加我们创建的类Serial和线程类QThread。
内容如下:
#ifndef MAINWIDGET_H
#define MAINWIDGET_H
#include <QWidget>
#include "serial.h" //添加自定义类serial头文件
#include <QThread> //添加线程类QThread头文件
QT_BEGIN_NAMESPACE
namespace Ui { class MainWidget; }
QT_END_NAMESPACE
class MainWidget : public QWidget
{
Q_OBJECT
public:
MainWidget(QWidget *parent = nullptr);
~MainWidget();
QThread *t1; //1.创建子线程对象
Serial *m_work; //2.创建任务类对象
private:
Ui::MainWidget *ui;
};
#endif // MAINWIDGET_H
在mainwidget.cpp中将创建的对象实例化,并将任务函数移入子线程。
内容如下:
#include "mainwidget.h"
#include "ui_mainwidget.h"
MainWidget::MainWidget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::MainWidget)
{
ui->setupUi(this);
//1.创建子线程对象,动态分配空间,指定父对象
t1 = new QThread(this);
//2.创建任务类对象,动态分配空间,不能指定父对象
m_work = new Serial;//防止内存泄漏,关闭窗口时 delete m_work;
//3.将任务对象移动到某个子线程中
m_work->moveToThread(t1);
}
MainWidget::~MainWidget()
{
delete ui;
delete m_work; //关闭时释放内存空间
}
初始化ui界面参数
在开始工作前需要初始化ui界面的参数,如设置QCombobox的下拉框内容。因此需要创建一个void initUI(void);函数。打开mainwidget.h,添加我们需要创建的函数,并使用快捷键alt+enter,在mainwidget.cpp中定义void initUI(void);函数。
设置内容如下:
public:
MainWidget(QWidget *parent = nullptr);
~MainWidget();
QThread *t1; //1.创建子线程对象
Serial *m_work; //2.创建任务类对象
void initUI(); //初始化UI界面参数,如设置QCombobox的item和设置QSS样式。
其中 void initUI(); 函数内容如下。
void MainWidget::initUI()
{
QStringList baudrateList; //设置波特率列表
baudrateList<<"1200"<<"2400"<<"4800"<<"9600"<<"19200"<<"38400"
<<"57600"<<"115200";
ui->comBaudRate->addItems(baudrateList); //将设置的Item加入到列表中
ui->comBaudRate->setEditable(true); //设置可以手动输入波特率
//限定波特率手动输入时只能输入数字且范围为(0, 1000000)即最高1M
isBaudRateRange= new QIntValidator; //防止内存泄漏,关闭窗口时 delete aIntValidator;
isBaudRateRange->setRange(0, 1000000);
ui->comBaudRate->setValidator(isBaudRateRange);
ui->comBaudRate->setCurrentIndex(3); //设置默认显示第4个即9600(从0开始)
QStringList databitsList; //设置数据位列表,根据串口中配置顺序设置。
databitsList<<"5"<<"6"<<"7"<<"8";
ui->comDataBits->addItems(databitsList); //将设置的Item加入到列表中
ui->comDataBits->setCurrentIndex(3); //设置默认显示第4个即8bit(从0开始)
QStringList parityList; //设置校验位列表,根据串口中配置顺序设置。
parityList<<"Even"<<"Mark"<<"None"<<"Odd"<<"Space";
ui->comParity->addItems(parityList); //将设置的Item加入到列表中
ui->comParity->setCurrentIndex(2); //设置默认显示第3个即None(从0开始)
QStringList stopbitsList; //设置停止位列表,根据串口中配置顺序设置。
stopbitsList<<"1"<<"1.5"<<"2";
ui->comStopBits->addItems(stopbitsList); //将设置的Item加入到列表中
ui->comStopBits->setCurrentIndex(0); //设置默认显示第1个即1bit(从0开始)
QStringList encodeList; //设置编码格式列表,根据编码格式中配置顺序设置。
encodeList<<"ASCII"<<"UTF8"<<"UTF16"<<"GBK"<<"Big5"<<"ShiftJIS";
ui->comEncode->addItems(encodeList); //将设置的Item加入到列表中
ui->comEncode->setCurrentIndex(0); //设置默认显示第1个即ASCII(从0开始)
}
注:
- 其中需要在mainwidget.h中添加 #include < QStringList > ;
- 配置的item参数需要同之前switch设置的参数顺序相同。
- 要在mainwidget.h中添加 #include < QIntValidator >;并创建一个私有成员,QIntValidator* isBaudRateRange;
设置完成后在MainWidget中运行 initUI(); 函数
MainWidget::MainWidget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::MainWidget)
{
ui->setupUi(this);
//0.初始化ui界面;
initUI();
//1.创建子线程对象,动态分配空间,指定父对象
t1 = new QThread(this);
//2.创建任务类对象,动态分配空间,不能指定父对象
m_work = new Serial;//防止内存泄漏,关闭窗口时 delete m_work;
//3.将任务对象移动到某个子线程中
m_work->moveToThread(t1);
}
至此,QCombobox 参数初始化完成。(后期仍会在 initUI() 中进行其他配置如设置QSS样式等)。
利用QSerialPortInfo得到串口号
这里我们会发现并没有设置串口的Item参数。主要原因是,电脑再识别设备的串口号时,会任意分配可用的端口号,因此这里我们通过使用QSerialPortInfo类来得到可用端口号,并设置到串口的Item中。
首先,打开mainwidget.h,添加 #include < QSerialPortInfo > , 然后创建 void getportInfo(); 函数,并使用快捷键alt+enter,在mainwidget.cpp 中定义 void getportInfo(); 函数。
实现步骤:
首先检测可用的设备端口号,当存在可用的端口号时,通过遍历的方式,将可用的端口号保存在portStringList中。然后设置到串口的Item中。无可用端口号时,弹出信号框。
具体内容如下:
void MainWidget::getportInfo()
{
qint32 comCnt=0; //保存当前可用的串口数量
QStringList portStringList; //保存当前可用的串口列表
if(portStringList.length()!=0)
{
portStringList.clear();//检测portStringList内容当不为空时清除再次调用时使用
}
if(ui->comPortName->count()!=0)
{
ui->comPortName->clear();//检测comPortName的列表数量当不为空时清除再次调用时使用
}
//获取串口设备数量
comCnt = QSerialPortInfo::availablePorts().length();
if(comCnt!=0)
{
//获取串口信息
foreach (const QSerialPortInfo &qspinfo, QSerialPortInfo::availablePorts())
{
portStringList+=qspinfo.portName();
}
ui->comPortName->addItems(portStringList);
}
else{
message("未检测到串口!");
}
}
注:
- 其中message();为自己重新封装的信号框函数,具体内容见下。
打开mainwidget.h,添加 #include < QMessageBox > , 然后重新封装函数 void message(const char *str); ,并使用快捷键alt+enter,在mainwidget.cpp 中定义 void message(const char *str);函数。
具体内容如下:
void MainWidget::message(const char *str)
{
QMessageBox msgBox;
msgBox.setText(QString::fromLocal8Bit(str));
msgBox.exec();
}
然后在MainWidget中运行 getportInfo(); 函数
这里要注意,在拔插串口设备时,可用的端口号会产生变化,但 getportInfo(); 函数仅在打开程序时运行一次,因此,这里需要增加更新端口号的方法。
实现方法:
- 添加检测拔插设备的函数,当设备变化时重新运行getportInfo();
- 使用定时器,设定每100ms检测一次,当设备变化时重新运行getportInfo();
- 增加按钮,当点击按钮时重新运行getportInfo();
这里选择增加按钮的方法,主要原因是简单且不占用资源。
增加按钮的信号与槽,当点击按钮时,重新运行getportInfo();
具体内容如下:
MainWidget::MainWidget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::MainWidget)
{
ui->setupUi(this);
//0.初始化ui界面;配置qss样式
initUI();
//1.创建子线程对象,动态分配空间,指定父对象
t1 = new QThread(this);
//2.创建任务类对象,动态分配空间,不能指定父对象
m_work = new Serial;//防止内存泄漏,关闭窗口时 delete m_work;
//3.将任务对象移动到某个子线程中
m_work->moveToThread(t1);
//4.获取串口设备信息
getportInfo();
//添加更新按钮信号与槽,用于更新串口设备信息
connect(ui->upBtn,&QPushButton::clicked,this,&MainWidget::getportInfo);
}