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

1、创建项目

实现串口助手

  • 创建 Qt Widgets Application 项目 seial

  • 基类选择 Widget

2、UI

  • UI设计

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

    <?xml version="1.0" encoding="UTF-8"?>
    <ui version="4.0">
    <class>Widget</class>
    <widget class="QWidget" name="Widget">
    <property name="geometry">
    <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>480</height>
    </rect>
    </property>
    <property name="windowTitle">
    <string>Widget</string>
    </property>
    <widget class="QWidget" name="layoutWidget">
    <property name="geometry">
    <rect>
    <x>31</x>
    <y>31</y>
    <width>737</width>
    <height>385</height>
    </rect>
    </property>
    <layout class="QGridLayout" name="gridLayout_3">
    <item row="0" column="0">
    <widget class="QPlainTextEdit" name="recvEdit">
    <property name="readOnly">
    <bool>true</bool>
    </property>
    </widget>
    </item>
    <item row="1" column="0">
    <spacer name="verticalSpacer">
    <property name="orientation">
    <enum>Qt::Vertical</enum>
    </property>
    <property name="sizeHint" stdset="0">
    <size>
    <width>20</width>
    <height>40</height>
    </size>
    </property>
    </spacer>
    </item>
    <item row="2" column="0">
    <layout class="QGridLayout" name="gridLayout_2">
    <item row="0" column="0">
    <layout class="QGridLayout" name="gridLayout">
    <item row="0" column="0">
    <widget class="QLabel" name="label_2">
    <property name="text">
    <string>波特率</string>
    </property>
    </widget>
    </item>
    <item row="0" column="1">
    <widget class="QComboBox" name="baundrateCb">
    <item>
    <property name="text">
    <string>4800</string>
    </property>
    </item>
    <item>
    <property name="text">
    <string>9600</string>
    </property>
    </item>
    <item>
    <property name="text">
    <string>115200</string>
    </property>
    </item>
    </widget>
    </item>
    <item row="1" column="0">
    <widget class="QLabel" name="label">
    <property name="text">
    <string>串口号</string>
    </property>
    </widget>
    </item>
    <item row="1" column="1">
    <widget class="QComboBox" name="serialCb"/>
    </item>
    <item row="2" column="0">
    <widget class="QLabel" name="label_5">
    <property name="text">
    <string>数据位</string>
    </property>
    </widget>
    </item>
    <item row="2" column="1">
    <widget class="QComboBox" name="dataCb">
    <item>
    <property name="text">
    <string>5</string>
    </property>
    </item>
    <item>
    <property name="text">
    <string>6</string>
    </property>
    </item>
    <item>
    <property name="text">
    <string>7</string>
    </property>
    </item>
    <item>
    <property name="text">
    <string>8</string>
    </property>
    </item>
    </widget>
    </item>
    <item row="3" column="0">
    <widget class="QLabel" name="label_4">
    <property name="text">
    <string>停止位</string>
    </property>
    </widget>
    </item>
    <item row="3" column="1">
    <widget class="QComboBox" name="stopCb">
    <item>
    <property name="text">
    <string>1</string>
    </property>
    </item>
    <item>
    <property name="text">
    <string>1.5</string>
    </property>
    </item>
    <item>
    <property name="text">
    <string>2</string>
    </property>
    </item>
    </widget>
    </item>
    <item row="4" column="0">
    <widget class="QLabel" name="label_3">
    <property name="text">
    <string>校验位</string>
    </property>
    </widget>
    </item>
    <item row="4" column="1">
    <widget class="QComboBox" name="checkCb">
    <item>
    <property name="text">
    <string>none</string>
    </property>
    </item>
    </widget>
    </item>
    </layout>
    </item>
    <item row="0" column="1">
    <spacer name="horizontalSpacer_4">
    <property name="orientation">
    <enum>Qt::Horizontal</enum>
    </property>
    <property name="sizeHint" stdset="0">
    <size>
    <width>40</width>
    <height>20</height>
    </size>
    </property>
    </spacer>
    </item>
    <item row="0" column="2">
    <layout class="QVBoxLayout" name="verticalLayout_2">
    <item>
    <widget class="QGroupBox" name="groupBox">
    <property name="title">
    <string>欢迎使用,这是一个信息框</string>
    </property>
    <widget class="QLabel" name="label_6">
    <property name="geometry">
    <rect>
    <x>120</x>
    <y>30</y>
    <width>161</width>
    <height>21</height>
    </rect>
    </property>
    <property name="text">
    <string>demo info...</string>
    </property>
    </widget>
    </widget>
    </item>
    <item>
    <widget class="QLineEdit" name="sendEdit"/>
    </item>
    <item>
    <layout class="QHBoxLayout" name="horizontalLayout_6">
    <item>
    <widget class="QPushButton" name="openBt">
    <property name="text">
    <string>打开串口</string>
    </property>
    </widget>
    </item>
    <item>
    <spacer name="horizontalSpacer">
    <property name="orientation">
    <enum>Qt::Horizontal</enum>
    </property>
    <property name="sizeHint" stdset="0">
    <size>
    <width>40</width>
    <height>20</height>
    </size>
    </property>
    </spacer>
    </item>
    <item>
    <widget class="QPushButton" name="closeBt">
    <property name="text">
    <string>关闭串口</string>
    </property>
    </widget>
    </item>
    <item>
    <spacer name="horizontalSpacer_2">
    <property name="orientation">
    <enum>Qt::Horizontal</enum>
    </property>
    <property name="sizeHint" stdset="0">
    <size>
    <width>40</width>
    <height>20</height>
    </size>
    </property>
    </spacer>
    </item>
    <item>
    <widget class="QPushButton" name="sendBt">
    <property name="text">
    <string>发送</string>
    </property>
    </widget>
    </item>
    <item>
    <spacer name="horizontalSpacer_3">
    <property name="orientation">
    <enum>Qt::Horizontal</enum>
    </property>
    <property name="sizeHint" stdset="0">
    <size>
    <width>40</width>
    <height>20</height>
    </size>
    </property>
    </spacer>
    </item>
    <item>
    <widget class="QPushButton" name="clearBt">
    <property name="text">
    <string>清空</string>
    </property>
    </widget>
    </item>
    </layout>
    </item>
    </layout>
    </item>
    </layout>
    </item>
    </layout>
    </widget>
    </widget>
    <layoutdefault spacing="6" margin="11"/>
    <resources/>
    <connections/>
    </ui>

3、逻辑功能

  1. 在工程文件中引入serialport

    QT       += core gui serialport
  2. 获取串口信息并展示到页面上,在目前 UI 对应的 cpp 的构造中进行

    说明:需要连接单片机才能显示串口号

    Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
    {
    ui->setupUi(this);
    QStringList serialNamePorts; // QSerialPort 是串口信息类,用于存放串口信息
    // QSerialPortInfo::availablePorts() 自动搜索可用串口,返回串口信息类对象的数组
    foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) { // 将得到的串口信息的串口号加入到 QStringList 中
    serialNamePorts<<info.portName();
    } // 将可用串口的列表显示到页面的下拉框中
    ui->serialCb->addItems(serialNamePorts);
    }
  3. 其他控件的逻辑功能

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

      • 对串口的声明和创建

        • 头文件

          #ifndef WIDGET_H
          #define WIDGET_H #include <QWidget>
          #include <QSerialPort> namespace Ui {
          class Widget;
          } class Widget : public QWidget
          {
          Q_OBJECT public:
          explicit Widget(QWidget *parent = 0);
          ~Widget();
          // 声明QSerialPort *serialPort
          QSerialPort *serialPort; private slots:
          void on_openBt_clicked(); void on_closeBt_clicked(); void on_sendBt_clicked(); void on_clearBt_clicked(); private:
          Ui::Widget *ui;
          }; #endif // WIDGET_H
        • Cpp文件

          #include "widget.h"
          #include "ui_widget.h"
          #include <QSerialPortInfo>
          #include <QMessageBox> Widget::Widget(QWidget *parent) :
          QWidget(parent),
          ui(new Ui::Widget)
          {
          ui->setupUi(this);
          // ... serialPort = new QSerialPort(this); // ...
          } Widget::~Widget()
          {
          delete serialPort;
          delete ui;
          }
      • 打开按钮单击信号的槽函数

        // 点击打开串口时将数据设置进串口并打开串口
        void Widget::on_openBt_clicked()
        {
        QSerialPort::BaudRate baudReat;
        QSerialPort::DataBits dataBits;
        QSerialPort::StopBits stopBits;
        QSerialPort::Parity checkBits; // 获取界面上的值
        switch(ui->baundrateCb->currentText().toInt()) {
        case QSerialPort::Baud4800:
        baudReat = QSerialPort::Baud4800;
        break;
        case QSerialPort::Baud9600:
        baudReat = QSerialPort::Baud9600;
        break;
        case QSerialPort::Baud115200:
        baudReat = QSerialPort::Baud115200;
        break;
        } switch(ui->dataCb->currentText().toInt()) {
        case QSerialPort::Data5:
        dataBits = QSerialPort::Data5;
        break;
        case QSerialPort::Data6:
        dataBits = QSerialPort::Data6;
        break;
        case QSerialPort::Data7:
        dataBits = QSerialPort::Data7;
        break;
        case QSerialPort::Data8:
        dataBits = QSerialPort::Data8;
        break;
        } int stopTmp = ui->stopCb->currentText().toInt();
        if (stopTmp == QSerialPort::OneStop) {
        stopBits = QSerialPort::OneStop;
        } else if (stopTmp == QSerialPort::OneAndHalfStop) {
        stopBits = QSerialPort::OneAndHalfStop;
        } else if (stopTmp == QSerialPort::TwoStop) {
        stopBits = QSerialPort::TwoStop;
        } if (ui->checkCb->currentText() == "none") {
        checkBits = QSerialPort::NoParity;
        } // 使用获取到的数据设置串口
        serialPort->setPortName(ui->serialCb->currentText());
        serialPort->setBaudRate(baudReat);
        serialPort->setDataBits(dataBits);
        serialPort->setStopBits(stopBits);
        serialPort->setParity(checkBits); // 打开串口,需要先判断串口是否打开成功
        if (serialPort->open(QIODevice::ReadWrite) == true) {
        QMessageBox::information(this, "提示", "success!");
        } else {
        QMessageBox::critical(this, "提示", "failed!");
        }
        }
      • 关闭按钮单击信号槽函数

        void Widget::on_closeBt_clicked()
        {
        serialPort->close();
        }
      • 发送按钮单击信号槽函数

        void Widget::on_sendBt_clicked()
        {
        // 将UI发送的QString转换为char* 类型,写入到serialPort
        serialPort->write(ui->sendEdit->text().toLocal8Bit().data());
        }
      • 串口有东西可读时,在接收框中进行展示

        • 定义槽函数,在头文件中

          #ifndef WIDGET_H
          #define WIDGET_H #include <QWidget>
          #include <QSerialPort> namespace Ui {
          class Widget;
          } class Widget : public QWidget
          {
          Q_OBJECT // ... private slots:
          // ...
          // 定义串口有东西可读时触发的槽函数
          void serialPortReadyRead_Slot(); // ...
          }; #endif // WIDGET_H
        • 手动绑定可读信号与槽函数,在构造中

          Widget::Widget(QWidget *parent) :
          QWidget(parent),
          ui(new Ui::Widget)
          {
          ui->setupUi(this);
          QStringList serialNamePorts; serialPort = new QSerialPort(this); // 手动关联读信号与自定义槽函数serialPortReadyRead_Slot(),串口有东西可读时触发槽函数
          connect(serialPort, SIGNAL(readyRead()), this, SLOT(serialPortReadyRead_Slot())); // ...
          }
        • 实现槽函数

          // 串口有东西可读时产生信号,触发槽函数
          void Widget::serialPortReadyRead_Slot()
          {
          // 接收UI中输入框的数据
          QString buffer = QString(serialPort->readAll());
          // 将接收到的数据显示到UI的recvEdit中
          ui->recvEdit->appendPlainText(buffer); }
      • 清除按钮单击信号槽函数

        void Widget::on_clearBt_clicked()
        {
        ui->recvEdit->clear();
        }

4、程序打包和部署

  1. 切换到 Release 模式进行编译

    由于缺少动态库,打包好的程序暂时还无法运行

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

    • 图示:

  2. 为打包好的程序更换图标

    需要使用.ico格式的图片

    • 将图标拷贝到工程目录下

    • 在工程文件中添加如下代码,再重新编译即可

      RC_ICONS = serial_icon.ico
  3. 封包操作,需要用到 Qt 的控制台

    • 创建一个新的目录,用于存放封包好的文件,不能包含中文路径

    • 将打包好的.exe文件拷贝到新的目录下

    • 从控制台进入新目录中cd /d C:\xxx\xxx

      D:\Tools\Qt\Qt5.11.1\5.11.1\mingw53_32>cd /d C:\Users\Dandelion\Desktop\SerialTools
      
      C:\Users\Dandelion\Desktop\SerialTools>dir
      驱动器 C 中的卷是 OS
      卷的序列号是 EAE6-1E0A C:\Users\Dandelion\Desktop\SerialTools 的目录 2023/03/10 02:22 <DIR> .
      2023/03/10 02:20 <DIR> ..
      2023/03/10 02:17 48,640 seial.exe
      1 个文件 48,640 字节
      2 个目录 63,272,501,248 可用字节 C:\Users\Dandelion\Desktop\SerialTools>
    • 使用windeployqt工具将动态库加到当前目录下:windeployqt seial.exe

      C:\Users\Dandelion\Desktop\SerialTools>windeployqt seial.exe
      C:\Users\Dandelion\Desktop\SerialTools\seial.exe 32 bit, release executable
      Adding Qt5Svg for qsvgicon.dll
      Skipping plugin qtvirtualkeyboardplugin.dll due to disabled dependencies (Qt5Qml Qt5Quick).
      Direct dependencies: Qt5Core Qt5Gui Qt5SerialPort Qt5Widgets
      All dependencies : Qt5Core Qt5Gui Qt5SerialPort Qt5Widgets
      To be deployed : Qt5Core Qt5Gui Qt5SerialPort Qt5Svg Qt5Widgets
      Updating Qt5Core.dll.
      Updating Qt5Gui.dll.
      Updating Qt5SerialPort.dll.
      Updating Qt5Svg.dll.
      Updating Qt5Widgets.dll.
      Updating libGLESV2.dll.
      Updating libEGL.dll.
      Updating D3Dcompiler_47.dll.
      Updating opengl32sw.dll.
      Updating libgcc_s_dw2-1.dll.
      Updating libstdc++-6.dll.
      Updating libwinpthread-1.dll.
      Patching Qt5Core.dll...
      Creating directory C:/Users/Dandelion/Desktop/SerialTools/iconengines.
      Updating qsvgicon.dll.
      Creating directory C:/Users/Dandelion/Desktop/SerialTools/imageformats.
      Updating qgif.dll.
      Updating qicns.dll.
      Updating qico.dll.
      Updating qjpeg.dll.
      Updating qsvg.dll.
      Updating qtga.dll.
      Updating qtiff.dll.
      Updating qwbmp.dll.
      Updating qwebp.dll.
      Creating directory C:/Users/Dandelion/Desktop/SerialTools/platforms.
      Updating qwindows.dll.
      Creating directory C:/Users/Dandelion/Desktop/SerialTools/styles.
      Updating qwindowsvistastyle.dll.
      Creating C:\Users\Dandelion\Desktop\SerialTools\translations...
      Creating qt_ar.qm...
      Creating qt_bg.qm...
      Creating qt_ca.qm...
      Creating qt_cs.qm...
      Creating qt_da.qm...
      Creating qt_de.qm...
      Creating qt_en.qm...
      Creating qt_es.qm...
      Creating qt_fi.qm...
      Creating qt_fr.qm...
      Creating qt_gd.qm...
      Creating qt_he.qm...
      Creating qt_hu.qm...
      Creating qt_it.qm...
      Creating qt_ja.qm...
      Creating qt_ko.qm...
      Creating qt_lv.qm...
      Creating qt_pl.qm...
      Creating qt_ru.qm...
      Creating qt_sk.qm...
      Creating qt_uk.qm... C:\Users\Dandelion\Desktop\SerialTools>

Qt 学习笔记 - 第三章 - Qt的三驾马车之一 - 串口编程 + 程序打包成Windows软件的更多相关文章

  1. Qt学习笔记-Widget布局管理

    Qt学习笔记4-Widget布局管理       以<C++ GUI Programming with Qt 4, Second Edition>为参考 实例:查找对话框 包含三个文件,f ...

  2. QT学习笔记(一)——Helloworld

    QT学习笔记(一)--Helloworld 一.调试的基本方法: Log调试法 --在代码中加入一定的打印语句 --打印程序状态和关键变量的值 断点调试法: --在开发环境中的对应代码行加上断点 -- ...

  3. CSS3秘笈第三版涵盖HTML5学习笔记1~5章

    第一部分----CSS基础知识 第1章,CSS需要的HTML HTML越简单,对搜索引擎越友好 div是块级元素,span是行内元素 <section>标签包含一组相关的内容,就像一本书中 ...

  4. qt学习笔记(五) QGraphicsPixmapItem与QGraphicsScene的编程实例 图标拖动渐变效果

    应大家的要求,还是把完整的project文件贴出来,大家省点事:http://www.kuaipan.cn/file/id_48923272389086450.htm 先看看执行效果,我用的群创7寸屏 ...

  5. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第九章:贴图

    原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第九章:贴图 代码工程地址: https://github.com/j ...

  6. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第一章:向量代数

    原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第一章:向量代数 学习目标: 学习如何使用几何学和数字描述 Vecto ...

  7. JVM学习笔记-第六章-类文件结构

    JVM学习笔记-第六章-类文件结构 6.3 Class类文件的结构 本章中,笔者只是通俗地将任意一个有效的类或接口锁应当满足的格式称为"Class文件格式",实际上它完全不需要以磁 ...

  8. JVM学习笔记-第七章-虚拟机类加载机制

    JVM学习笔记-第七章-虚拟机类加载机制 7.1 概述 Java虚拟机描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这个过程被 ...

  9. 《Java核心技术·卷Ⅰ:基础知识(原版10》学习笔记 第5章 继承

    <Java核心技术·卷Ⅰ:基础知识(原版10>学习笔记 第5章 继承 目录 <Java核心技术·卷Ⅰ:基础知识(原版10>学习笔记 第5章 继承 5.1 类.超类和子类 5.1 ...

  10. Stealth视频教程学习笔记(第二章)

    Stealth视频教程学习笔记(第二章) 本文是对Unity官方视频教程Stealth的学习笔记.在此之前,本人整理了Stealth视频的英文字幕,并放到了优酷上.本文将分别对各个视频进行学习总结,提 ...

随机推荐

  1. 页面-vue

    1.安装node.js 语言-页面-开发环境-node.js,webpack,安装 - hehehenhen - 博客园 (cnblogs.com) 2.安装webpack 语言-页面-开发-webp ...

  2. 杭电oj 数值统计

    Problem Description 统计给定的n个数中,负数.零和正数的个数.   Input 输入数据有多组,每组占一行,每行的第一个数是整数n(n<100),表示需要统计的数值的个数,然 ...

  3. sed编辑器

    sed sed是一个非交互式的流文本编辑器,可实现增删改查,广泛适用于shell脚本中 工作原理 sed每次只从文本或标准输入中读取一行数据,将其拷贝到一个编辑缓冲区,然后对其如同命令一般处理,并显示 ...

  4. 攻防世界Web篇——unserialize3

    知识点: 序列化与反序列化维基百科:    序列化(serialization)在计算机科学的数据处理中,是指将数据结构或对象状态转换成可取用格式(例如存成文件,存于缓冲,或经由网络中发送),以留待后 ...

  5. omcat启动Publishing failed with multiple errors

    新安装一个tomcat插件.启动的时候就弹错误框.但tomcat还能使用. Publishingfailedwithmultipleerrors Resource is out of sync wit ...

  6. Mardown学习

    Mardown学习 标题: 一级标题:'#'+'空格'+'标题名字'+'回车' 二级标题:'##'+'空格'+'标题名字'+'回车' 三级标题:'###'+'空格'+'标题名字'+'回车' 四级标题: ...

  7. element select多选选项卡页面抖动问题

    最近做项目是有个功能需要下拉框多选,然后碰到了一个问题就是选择选项的时候出现频繁抖动的情况 问题描述: 页面选择到三个选项时长度为三的时候就会开始抖动,其他长度没有问题,检索elements是发现选择 ...

  8. C++ 复习函数的基本知识

    C++ 复习函数的基本知识 要使用 C++ 函数,必须完成如下工作: 1. 提供函数定义: 2. 提供函数原型: 3. 调用函数. 例子: #include <iostream> usin ...

  9. PINNs的网络大小与过拟合

    PINNs中网络越大时,会不会产生过拟合呢 虽然PINNs可以不用到数据,但是我认为物理约束所带来的信息也是有限的 因此当网络变得很大时,也有可能产生过拟合现象吧 但是在神经元分裂那篇文章中,训练停滞 ...

  10. Nacos 之 Distro 协议

    1. 概述 Distro协议是阿里自研的一个最终一致性协议,继承了 Gossip 以及 Eureka 通信(PeerEurekaNodes)的优点并做进一步优化而出来的: 对于原生的Gossip,由于 ...