沉沦之枫叶 发表于 2021-10-29 22:46:24

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;//关闭时释放内存空间
}
注:这里线程操作参考之前的文章Qt多线程的使用记录中的方式二。初始化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();
这里选择增加按钮的方法,主要原因是简单且不占用资源。https://gitee.com/cltzq/picture/raw/master/img3/202110282346391.png增加按钮的信号与槽,当点击按钮时,重新运行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);

}
至此,利用QSerialPortInfo得到串口号完成。参考资料 Qt多线程的使用记录: https://blog.csdn.net/qq_39538318/article/details/120398160

Memory# 发表于 2021-10-30 14:24:40

:lol:lol:lol:lol
页: [1]
查看完整版本: QT5串口上位机——从零开始教你写03