Qt 学习笔记 - 第三章 - Qt的三驾马车之一 - 串口编程 + 程序打包成Windows软件
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代码展示
<?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、逻辑功能
在工程文件中引入
serialportQT += core gui serialport
获取串口信息并展示到页面上,在目前 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);
}
其他控件的逻辑功能
点击打开串口时对串口进行初始化
对串口的声明和创建
头文件
#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_HCpp文件
#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、程序打包和部署
切换到 Release 模式进行编译
由于缺少动态库,打包好的程序暂时还无法运行
导出文件位置:位于项目目录所在路径下,文件名以 Release 结尾,如:
build-seial-Desktop_Qt_5_11_1_MinGW_32bit-Release图示:

为打包好的程序更换图标
需要使用
.ico格式的图片将图标拷贝到工程目录下
在工程文件中添加如下代码,再重新编译即可
RC_ICONS = serial_icon.ico
封包操作,需要用到 Qt 的控制台
创建一个新的目录,用于存放封包好的文件,不能包含中文路径
将打包好的
.exe文件拷贝到新的目录下从控制台进入新目录中
cd /d C:\xxx\xxxD:\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.exeC:\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软件的更多相关文章
- Qt学习笔记-Widget布局管理
Qt学习笔记4-Widget布局管理 以<C++ GUI Programming with Qt 4, Second Edition>为参考 实例:查找对话框 包含三个文件,f ...
- QT学习笔记(一)——Helloworld
QT学习笔记(一)--Helloworld 一.调试的基本方法: Log调试法 --在代码中加入一定的打印语句 --打印程序状态和关键变量的值 断点调试法: --在开发环境中的对应代码行加上断点 -- ...
- CSS3秘笈第三版涵盖HTML5学习笔记1~5章
第一部分----CSS基础知识 第1章,CSS需要的HTML HTML越简单,对搜索引擎越友好 div是块级元素,span是行内元素 <section>标签包含一组相关的内容,就像一本书中 ...
- qt学习笔记(五) QGraphicsPixmapItem与QGraphicsScene的编程实例 图标拖动渐变效果
应大家的要求,还是把完整的project文件贴出来,大家省点事:http://www.kuaipan.cn/file/id_48923272389086450.htm 先看看执行效果,我用的群创7寸屏 ...
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第九章:贴图
原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第九章:贴图 代码工程地址: https://github.com/j ...
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第一章:向量代数
原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第一章:向量代数 学习目标: 学习如何使用几何学和数字描述 Vecto ...
- JVM学习笔记-第六章-类文件结构
JVM学习笔记-第六章-类文件结构 6.3 Class类文件的结构 本章中,笔者只是通俗地将任意一个有效的类或接口锁应当满足的格式称为"Class文件格式",实际上它完全不需要以磁 ...
- JVM学习笔记-第七章-虚拟机类加载机制
JVM学习笔记-第七章-虚拟机类加载机制 7.1 概述 Java虚拟机描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这个过程被 ...
- 《Java核心技术·卷Ⅰ:基础知识(原版10》学习笔记 第5章 继承
<Java核心技术·卷Ⅰ:基础知识(原版10>学习笔记 第5章 继承 目录 <Java核心技术·卷Ⅰ:基础知识(原版10>学习笔记 第5章 继承 5.1 类.超类和子类 5.1 ...
- Stealth视频教程学习笔记(第二章)
Stealth视频教程学习笔记(第二章) 本文是对Unity官方视频教程Stealth的学习笔记.在此之前,本人整理了Stealth视频的英文字幕,并放到了优酷上.本文将分别对各个视频进行学习总结,提 ...
随机推荐
- 基于ALSA库实现音频采集和播放遇到的问题
最近基于Linux系统C语言实现音频的采集和播放,建立了两个子线程,一个通过调用snd_pcm_readi来实现采集数据,并存入FIFO中,另一个从FIFO中取数据并通过udp的sendto发送出去, ...
- 【IDEA】测试类(test)的模板及定义
人和动物的区别是:能制造和使用工具.因为,工具大大便利了我们的生活. 我们在使用Idea开发java项目的过程中,有些代码是固定的,我们能不能只写几个字,就代表一连串的代码.例如,这里,我们只是输入了 ...
- C/C++:printf 函数格式化输出,用法详细记录
printf ( print format )函数是接触C/C++之后接触的第一个函数,它的功能除了输出hello world外,更重要的是进行格式化输出,比如输出整数的%d,输出小数的%f,%lf ...
- iOS 15 UI适配
1. UINavigationBar 在iOS 15中,UINavigationBar默认为透明.在滑动时会有模糊效果.如果想要一直就是模糊效果,可以通过改变scrollEdgeAppearance属 ...
- 错题笔记:只有浮点型float double可以装小数
char是不能表示小数的,如果赋值小数 则小数部分直接省略.
- noi 1.1 5 输出保留12位小数的浮点数
描述 读入一个双精度浮点数,保留12位小数,输出这个浮点数. 输入 只有一行,一个双精度浮点数. 输出 也只有一行,保留12位小数的浮点数. 样例输入 3.1415926535798932 样例输出 ...
- 项目实训DAY6
今天主要的工作是把功能界面丰富了一下,查阅了一下论文,将页面中添加了可视化元素:同时决定了最后几天的工作计划.
- Python使用双层列表推导式输出九九乘法表
print('\n'.join([' '.join(['%2d *%2d = %2d' % (col, row, col * row) for col in range(1, row + 1)]) f ...
- 微信小程序基本总结
小程序目录结构 project.config.json 配置项目文件,用的最多的就是配置是否开启HTTPS校检 app.js 设置一些全局的基础数据 app.json 设置底部tabbar,标题栏和路 ...
- Spring系列之资源-11
目录 `Resource` 内置`Resource`实现 `UrlResource` `ClassPathResource` `FileSystemResource` `ServletContextR ...