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开始)

}

注:

  1. 其中需要在mainwidget.h中添加 #include < QStringList > ;
  2. 配置的item参数需要同之前switch设置的参数顺序相同。
  3. 要在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("未检测到串口!");
        }
}

注:

  1. 其中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(); 函数仅在打开程序时运行一次,因此,这里需要增加更新端口号的方法。

实现方法:

  1. 添加检测拔插设备的函数,当设备变化时重新运行getportInfo();
  2. 使用定时器,设定每100ms检测一次,当设备变化时重新运行getportInfo();
  3. 增加按钮,当点击按钮时重新运行getportInfo();

这里选择增加按钮的方法,主要原因是简单且不占用资源。

python串口 上位机 串口程序上位机编写_qt

增加按钮的信号与槽,当点击按钮时,重新运行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);

}