Qt 学习笔记 - 第三章 - Qt的三驾马车之一 - 串口编程 + 程序打包成Windows ...

王柳  金牌会员 | 2023-3-10 02:52:00 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 892|帖子 892|积分 2676

Qt 学习笔记全系列传送门:

目录

1、创建项目

实现串口助手


  • 创建 Qt Widgets Application 项目 seial
  • 基类选择 Widget
2、UI


  • UI设计

    • 接收框组件,在分类 Input Widgets 中,Plain Text Edit 组件(QPlainTextEdit),双击可以编辑选项,置顶项为默认选择属性,勾选组件的只读属性 readOnly
    • 属性选择,在分类 Input Widgets 中,Combo Box 组件(QComboBox)
    • 发送框,在分类在 Input Widgets 中,Line Edit 组件(QLineEdit)
    • 信息框,写个广告之类的可以使用,在分类  中,Group Box 组件(QGroupBox)
    • 控件改名

  • UI代码展示
    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <ui version="4.0">
    3. <class>Widget</class>
    4. <widget  name="Widget">
    5.   <property name="geometry">
    6.    <rect>
    7.     <x>0</x>
    8.     <y>0</y>
    9.     <width>800</width>
    10.     <height>480</height>
    11.    </rect>
    12.   </property>
    13.   <property name="windowTitle">
    14.    <string>Widget</string>
    15.   </property>
    16.   <widget  name="layoutWidget">
    17.    <property name="geometry">
    18.     <rect>
    19.      <x>31</x>
    20.      <y>31</y>
    21.      <width>737</width>
    22.      <height>385</height>
    23.     </rect>
    24.    </property>
    25.    <layout  name="gridLayout_3">
    26.     <item row="0" column="0">
    27.      <widget  name="recvEdit">
    28.       <property name="readOnly">
    29.        <bool>true</bool>
    30.       </property>
    31.      </widget>
    32.     </item>
    33.     <item row="1" column="0">
    34.      <spacer name="verticalSpacer">
    35.       <property name="orientation">
    36.        <enum>Qt::Vertical</enum>
    37.       </property>
    38.       <property name="sizeHint" stdset="0">
    39.        <size>
    40.         <width>20</width>
    41.         <height>40</height>
    42.        </size>
    43.       </property>
    44.      </spacer>
    45.     </item>
    46.     <item row="2" column="0">
    47.      <layout  name="gridLayout_2">
    48.       <item row="0" column="0">
    49.        <layout  name="gridLayout">
    50.         <item row="0" column="0">
    51.          <widget  name="label_2">
    52.           <property name="text">
    53.            <string>波特率</string>
    54.           </property>
    55.          </widget>
    56.         </item>
    57.         <item row="0" column="1">
    58.          <widget  name="baundrateCb">
    59.           <item>
    60.            <property name="text">
    61.             <string>4800</string>
    62.            </property>
    63.           </item>
    64.           <item>
    65.            <property name="text">
    66.             <string>9600</string>
    67.            </property>
    68.           </item>
    69.           <item>
    70.            <property name="text">
    71.             <string>115200</string>
    72.            </property>
    73.           </item>
    74.          </widget>
    75.         </item>
    76.         <item row="1" column="0">
    77.          <widget  name="label">
    78.           <property name="text">
    79.            <string>串口号</string>
    80.           </property>
    81.          </widget>
    82.         </item>
    83.         <item row="1" column="1">
    84.          <widget  name="serialCb"/>
    85.         </item>
    86.         <item row="2" column="0">
    87.          <widget  name="label_5">
    88.           <property name="text">
    89.            <string>数据位</string>
    90.           </property>
    91.          </widget>
    92.         </item>
    93.         <item row="2" column="1">
    94.          <widget  name="dataCb">
    95.           <item>
    96.            <property name="text">
    97.             <string>5</string>
    98.            </property>
    99.           </item>
    100.           <item>
    101.            <property name="text">
    102.             <string>6</string>
    103.            </property>
    104.           </item>
    105.           <item>
    106.            <property name="text">
    107.             <string>7</string>
    108.            </property>
    109.           </item>
    110.           <item>
    111.            <property name="text">
    112.             <string>8</string>
    113.            </property>
    114.           </item>
    115.          </widget>
    116.         </item>
    117.         <item row="3" column="0">
    118.          <widget  name="label_4">
    119.           <property name="text">
    120.            <string>停止位</string>
    121.           </property>
    122.          </widget>
    123.         </item>
    124.         <item row="3" column="1">
    125.          <widget  name="stopCb">
    126.           <item>
    127.            <property name="text">
    128.             <string>1</string>
    129.            </property>
    130.           </item>
    131.           <item>
    132.            <property name="text">
    133.             <string>1.5</string>
    134.            </property>
    135.           </item>
    136.           <item>
    137.            <property name="text">
    138.             <string>2</string>
    139.            </property>
    140.           </item>
    141.          </widget>
    142.         </item>
    143.         <item row="4" column="0">
    144.          <widget  name="label_3">
    145.           <property name="text">
    146.            <string>校验位</string>
    147.           </property>
    148.          </widget>
    149.         </item>
    150.         <item row="4" column="1">
    151.          <widget  name="checkCb">
    152.           <item>
    153.            <property name="text">
    154.             <string>none</string>
    155.            </property>
    156.           </item>
    157.          </widget>
    158.         </item>
    159.        </layout>
    160.       </item>
    161.       <item row="0" column="1">
    162.        <spacer name="horizontalSpacer_4">
    163.         <property name="orientation">
    164.          <enum>Qt::Horizontal</enum>
    165.         </property>
    166.         <property name="sizeHint" stdset="0">
    167.          <size>
    168.           <width>40</width>
    169.           <height>20</height>
    170.          </size>
    171.         </property>
    172.        </spacer>
    173.       </item>
    174.       <item row="0" column="2">
    175.        <layout  name="verticalLayout_2">
    176.         <item>
    177.          <widget  name="groupBox">
    178.           <property name="title">
    179.            <string>欢迎使用,这是一个信息框</string>
    180.           </property>
    181.           <widget  name="label_6">
    182.            <property name="geometry">
    183.             <rect>
    184.              <x>120</x>
    185.              <y>30</y>
    186.              <width>161</width>
    187.              <height>21</height>
    188.             </rect>
    189.            </property>
    190.            <property name="text">
    191.             <string>demo info...</string>
    192.            </property>
    193.           </widget>
    194.          </widget>
    195.         </item>
    196.         <item>
    197.          <widget  name="sendEdit"/>
    198.         </item>
    199.         <item>
    200.          <layout  name="horizontalLayout_6">
    201.           <item>
    202.            <widget  name="openBt">
    203.             <property name="text">
    204.              <string>打开串口</string>
    205.             </property>
    206.            </widget>
    207.           </item>
    208.           <item>
    209.            <spacer name="horizontalSpacer">
    210.             <property name="orientation">
    211.              <enum>Qt::Horizontal</enum>
    212.             </property>
    213.             <property name="sizeHint" stdset="0">
    214.              <size>
    215.               <width>40</width>
    216.               <height>20</height>
    217.              </size>
    218.             </property>
    219.            </spacer>
    220.           </item>
    221.           <item>
    222.            <widget  name="closeBt">
    223.             <property name="text">
    224.              <string>关闭串口</string>
    225.             </property>
    226.            </widget>
    227.           </item>
    228.           <item>
    229.            <spacer name="horizontalSpacer_2">
    230.             <property name="orientation">
    231.              <enum>Qt::Horizontal</enum>
    232.             </property>
    233.             <property name="sizeHint" stdset="0">
    234.              <size>
    235.               <width>40</width>
    236.               <height>20</height>
    237.              </size>
    238.             </property>
    239.            </spacer>
    240.           </item>
    241.           <item>
    242.            <widget  name="sendBt">
    243.             <property name="text">
    244.              <string>发送</string>
    245.             </property>
    246.            </widget>
    247.           </item>
    248.           <item>
    249.            <spacer name="horizontalSpacer_3">
    250.             <property name="orientation">
    251.              <enum>Qt::Horizontal</enum>
    252.             </property>
    253.             <property name="sizeHint" stdset="0">
    254.              <size>
    255.               <width>40</width>
    256.               <height>20</height>
    257.              </size>
    258.             </property>
    259.            </spacer>
    260.           </item>
    261.           <item>
    262.            <widget  name="clearBt">
    263.             <property name="text">
    264.              <string>清空</string>
    265.             </property>
    266.            </widget>
    267.           </item>
    268.          </layout>
    269.         </item>
    270.        </layout>
    271.       </item>
    272.      </layout>
    273.     </item>
    274.    </layout>
    275.   </widget>
    276. </widget>
    277. <layoutdefault spacing="6" margin="11"/>
    278. <resources/>
    279. <connections/>
    280. </ui>
    复制代码
3、逻辑功能


  • 在工程文件中引入serialport
    1. QT       += core gui serialport
    复制代码
  • 获取串口信息并展示到页面上,在目前 UI 对应的 cpp 的构造中进行
    说明:需要连接单片机才能显示串口号
    1. Widget::Widget(QWidget *parent) :
    2.     QWidget(parent),
    3.     ui(new Ui::Widget)
    4. {
    5.     ui->setupUi(this);
    6.     QStringList serialNamePorts;
    7.     // QSerialPort 是串口信息类,用于存放串口信息
    8.     // QSerialPortInfo::availablePorts() 自动搜索可用串口,返回串口信息类对象的数组
    9.     foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
    10.         // 将得到的串口信息的串口号加入到 QStringList 中
    11.         serialNamePorts<<info.portName();
    12.     }
    13.     // 将可用串口的列表显示到页面的下拉框中
    14.     ui->serialCb->addItems(serialNamePorts);
    15. }
    复制代码
  • 其他控件的逻辑功能

    • 点击打开串口时对串口进行初始化

      • 对串口的声明和创建

        • 头文件
          1. #ifndef WIDGET_H
          2. #define WIDGET_H
          3. #include <QWidget>
          4. #include <QSerialPort>
          5. namespace Ui {
          6. class Widget;
          7. }
          8. class Widget : public QWidget
          9. {
          10.     Q_OBJECT
          11. public:
          12.     explicit Widget(QWidget *parent = 0);
          13.     ~Widget();
          14.     // 声明QSerialPort *serialPort
          15.     QSerialPort *serialPort;
          16. private slots:
          17.     void on_openBt_clicked();
          18.     void on_closeBt_clicked();
          19.     void on_sendBt_clicked();
          20.    
          21.     void on_clearBt_clicked();
          22.    
          23. private:
          24.     Ui::Widget *ui;
          25. };
          26. #endif // WIDGET_H
          复制代码
        • Cpp文件
          1. #include "widget.h"
          2. #include "ui_widget.h"
          3. #include <QSerialPortInfo>
          4. #include <QMessageBox>
          5. Widget::Widget(QWidget *parent) :
          6.     QWidget(parent),
          7.     ui(new Ui::Widget)
          8. {
          9.     ui->setupUi(this);
          10.     // ...
          11.     serialPort = new QSerialPort(this);
          12.     // ...
          13. }
          14. Widget::~Widget()
          15. {
          16.     delete serialPort;
          17.     delete ui;
          18. }
          复制代码

      • 打开按钮单击信号的槽函数
        1. // 点击打开串口时将数据设置进串口并打开串口
        2. void Widget::on_openBt_clicked()
        3. {
        4.     QSerialPort::BaudRate baudReat;
        5.     QSerialPort::DataBits dataBits;
        6.     QSerialPort::StopBits stopBits;
        7.     QSerialPort::Parity checkBits;
        8.     // 获取界面上的值
        9.     switch(ui->baundrateCb->currentText().toInt()) {
        10.     case QSerialPort::Baud4800:
        11.         baudReat = QSerialPort::Baud4800;
        12.         break;
        13.     case QSerialPort::Baud9600:
        14.         baudReat = QSerialPort::Baud9600;
        15.         break;
        16.     case QSerialPort::Baud115200:
        17.         baudReat = QSerialPort::Baud115200;
        18.         break;
        19.     }
        20.     switch(ui->dataCb->currentText().toInt()) {
        21.     case QSerialPort::Data5:
        22.         dataBits = QSerialPort::Data5;
        23.         break;
        24.     case QSerialPort::Data6:
        25.         dataBits = QSerialPort::Data6;
        26.         break;
        27.     case QSerialPort::Data7:
        28.         dataBits = QSerialPort::Data7;
        29.         break;
        30.     case QSerialPort::Data8:
        31.         dataBits = QSerialPort::Data8;
        32.         break;
        33.     }
        34.     int stopTmp = ui->stopCb->currentText().toInt();
        35.     if (stopTmp == QSerialPort::OneStop) {
        36.         stopBits = QSerialPort::OneStop;
        37.     } else if (stopTmp == QSerialPort::OneAndHalfStop) {
        38.         stopBits = QSerialPort::OneAndHalfStop;
        39.     } else if (stopTmp == QSerialPort::TwoStop) {
        40.         stopBits = QSerialPort::TwoStop;
        41.     }
        42.     if (ui->checkCb->currentText() == "none") {
        43.         checkBits = QSerialPort::NoParity;
        44.     }
        45.     // 使用获取到的数据设置串口
        46.     serialPort->setPortName(ui->serialCb->currentText());
        47.     serialPort->setBaudRate(baudReat);
        48.     serialPort->setDataBits(dataBits);
        49.     serialPort->setStopBits(stopBits);
        50.     serialPort->setParity(checkBits);
        51.     // 打开串口,需要先判断串口是否打开成功
        52.     if (serialPort->open(QIODevice::ReadWrite) == true) {
        53.         QMessageBox::information(this, "提示", "success!");
        54.     } else {
        55.         QMessageBox::critical(this, "提示", "failed!");
        56.     }
        57. }
        复制代码
      • 关闭按钮单击信号槽函数
        1. void Widget::on_closeBt_clicked()
        2. {
        3.     serialPort->close();
        4. }
        复制代码
      • 发送按钮单击信号槽函数
        1. void Widget::on_sendBt_clicked()
        2. {
        3.     // 将UI发送的QString转换为char* 类型,写入到serialPort
        4.     serialPort->write(ui->sendEdit->text().toLocal8Bit().data());
        5. }
        复制代码
      • 串口有东西可读时,在接收框中进行展示

        • 定义槽函数,在头文件中
          1. #ifndef WIDGET_H
          2. #define WIDGET_H
          3. #include <QWidget>
          4. #include <QSerialPort>
          5. namespace Ui {
          6. class Widget;
          7. }
          8. class Widget : public QWidget
          9. {
          10.     Q_OBJECT
          11. // ...
          12. private slots:
          13.         // ...
          14.     // 定义串口有东西可读时触发的槽函数
          15.     void serialPortReadyRead_Slot();
          16. // ...
          17. };
          18. #endif // WIDGET_H
          复制代码
        • 手动绑定可读信号与槽函数,在构造中
          1. Widget::Widget(QWidget *parent) :
          2.     QWidget(parent),
          3.     ui(new Ui::Widget)
          4. {
          5.     ui->setupUi(this);
          6.     QStringList serialNamePorts;
          7.     serialPort = new QSerialPort(this);
          8.     // 手动关联读信号与自定义槽函数serialPortReadyRead_Slot(),串口有东西可读时触发槽函数
          9.     connect(serialPort, SIGNAL(readyRead()), this, SLOT(serialPortReadyRead_Slot()));
          10.         // ...
          11. }
          复制代码
        • 实现槽函数
          1. // 串口有东西可读时产生信号,触发槽函数
          2. void Widget::serialPortReadyRead_Slot()
          3. {
          4.     // 接收UI中输入框的数据
          5.     QString buffer = QString(serialPort->readAll());
          6.     // 将接收到的数据显示到UI的recvEdit中
          7.     ui->recvEdit->appendPlainText(buffer);
          8. }
          复制代码

      • 清除按钮单击信号槽函数
        1. void Widget::on_clearBt_clicked()
        2. {
        3.     ui->recvEdit->clear();
        4. }
        复制代码


4、程序打包和部署


  • 切换到 Release 模式进行编译
    由于缺少动态库,打包好的程序暂时还无法运行


    • 导出文件位置:位于项目目录所在路径下,文件名以 Release 结尾,如:build-seial-Desktop_Qt_5_11_1_MinGW_32bit-Release
    • 图示:


  • 为打包好的程序更换图标
    需要使用.ico格式的图片


    • 将图标拷贝到工程目录下
    • 在工程文件中添加如下代码,再重新编译即可
      1. RC_ICONS = serial_icon.ico
      复制代码

  • 封包操作,需要用到 Qt 的控制台

    • 创建一个新的目录,用于存放封包好的文件,不能包含中文路径
    • 将打包好的.exe文件拷贝到新的目录下
    • 从控制台进入新目录中cd /d C:\xxx\xxx
      1. D:\Tools\Qt\Qt5.11.1\5.11.1\mingw53_32>cd /d C:\Users\Dandelion\Desktop\SerialTools
      2. C:\Users\Dandelion\Desktop\SerialTools>dir
      3. 驱动器 C 中的卷是 OS
      4. 卷的序列号是 EAE6-1E0A
      5. C:\Users\Dandelion\Desktop\SerialTools 的目录
      6. 2023/03/10  02:22    <DIR>          .
      7. 2023/03/10  02:20    <DIR>          ..
      8. 2023/03/10  02:17            48,640 seial.exe
      9.                1 个文件         48,640 字节
      10.                2 个目录 63,272,501,248 可用字节
      11. C:\Users\Dandelion\Desktop\SerialTools>
      复制代码
    • 使用windeployqt工具将动态库加到当前目录下:windeployqt seial.exe
      1. C:\Users\Dandelion\Desktop\SerialTools>windeployqt seial.exe
      2. C:\Users\Dandelion\Desktop\SerialTools\seial.exe 32 bit, release executable
      3. Adding Qt5Svg for qsvgicon.dll
      4. Skipping plugin qtvirtualkeyboardplugin.dll due to disabled dependencies (Qt5Qml Qt5Quick).
      5. Direct dependencies: Qt5Core Qt5Gui Qt5SerialPort Qt5Widgets
      6. All dependencies   : Qt5Core Qt5Gui Qt5SerialPort Qt5Widgets
      7. To be deployed     : Qt5Core Qt5Gui Qt5SerialPort Qt5Svg Qt5Widgets
      8. Updating Qt5Core.dll.
      9. Updating Qt5Gui.dll.
      10. Updating Qt5SerialPort.dll.
      11. Updating Qt5Svg.dll.
      12. Updating Qt5Widgets.dll.
      13. Updating libGLESV2.dll.
      14. Updating libEGL.dll.
      15. Updating D3Dcompiler_47.dll.
      16. Updating opengl32sw.dll.
      17. Updating libgcc_s_dw2-1.dll.
      18. Updating libstdc++-6.dll.
      19. Updating libwinpthread-1.dll.
      20. Patching Qt5Core.dll...
      21. Creating directory C:/Users/Dandelion/Desktop/SerialTools/iconengines.
      22. Updating qsvgicon.dll.
      23. Creating directory C:/Users/Dandelion/Desktop/SerialTools/imageformats.
      24. Updating qgif.dll.
      25. Updating qicns.dll.
      26. Updating qico.dll.
      27. Updating qjpeg.dll.
      28. Updating qsvg.dll.
      29. Updating qtga.dll.
      30. Updating qtiff.dll.
      31. Updating qwbmp.dll.
      32. Updating qwebp.dll.
      33. Creating directory C:/Users/Dandelion/Desktop/SerialTools/platforms.
      34. Updating qwindows.dll.
      35. Creating directory C:/Users/Dandelion/Desktop/SerialTools/styles.
      36. Updating qwindowsvistastyle.dll.
      37. Creating C:\Users\Dandelion\Desktop\SerialTools\translations...
      38. Creating qt_ar.qm...
      39. Creating qt_bg.qm...
      40. Creating qt_ca.qm...
      41. Creating qt_cs.qm...
      42. Creating qt_da.qm...
      43. Creating qt_de.qm...
      44. Creating qt_en.qm...
      45. Creating qt_es.qm...
      46. Creating qt_fi.qm...
      47. Creating qt_fr.qm...
      48. Creating qt_gd.qm...
      49. Creating qt_he.qm...
      50. Creating qt_hu.qm...
      51. Creating qt_it.qm...
      52. Creating qt_ja.qm...
      53. Creating qt_ko.qm...
      54. Creating qt_lv.qm...
      55. Creating qt_pl.qm...
      56. Creating qt_ru.qm...
      57. Creating qt_sk.qm...
      58. Creating qt_uk.qm...
      59. C:\Users\Dandelion\Desktop\SerialTools>
      复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

王柳

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表