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视频的英文字幕,并放到了优酷上.本文将分别对各个视频进行学习总结,提 ...
随机推荐
- jmeter中返回值提取并存储。
jmeter中,关于对接口提取值如何存入CSV文件并且做到换列操作的处理.我这里简单介绍一下. 1.首先把接口调通(这个是必须条件),确认好需要提取存入csv的字段,这里以统计token跟userid ...
- Docker 环境下如何配置你的镜像(基础)
一 .镜像操作 重命名镜像:docker tag 查看镜像: docker images 镜像删除: docker rmi 启动容器: docker run 基于已有 ...
- Docker info 查看报错 WARNING: No swap limit support 解决
docker可以通过启动命令来限制容器可以使用的最大物理内存和swap,但是通常在使用这些命令的时候经常会碰到"WARNING: No swap limit support"警告 ...
- 版图 shrink
先打开模拟部分的版图,然后在ciw 里面执行 dbCreateXFormPCell(geGetEditCellView() "libName") 然后在"libName& ...
- 【相关杂项】stdio.h中的sprintf函数/union的作用
1.定义int sprintf(char *str, const char *format, ...) 1.paras:*str:目标字符串首指针 *format:要写入目标字符串的 ...
- Go的目录及其含义
运行 go env 找到go的运行目录,可以看到下边有三个文件: bin存放编译后的可执行文件(go install 自动创建),pkg存放编译后的包文件(go install 自动创建),src存放 ...
- Linux 使用Apache服务部署静态网站
网站服务程序 我们平时访问的网站服务就是Web网络服务,一般是指允许用户通过浏览器访问到互联网中各种资源的服务.如图所示,Web网络服务是一种被动访问的服务程序,即只有接收到互联网中其他主机发出的请求 ...
- 写一些Linux文件夹操作的一些感悟。
rwx 权限 对目录的作用 读权限(r) 表示具有读取目录结构列表的权限,也就是说,可以看到目录中有哪些文件和子目录.一旦对目录拥有 r 权限,就可以在此目录下执行 ls 命令,查看目录中的内容. 写 ...
- Dom,Bom的用法
DOM DOM 全称document object model 文档对象模型 操作HTML HTML文档有HTML+css组成 DOM 利用js操作HTML+css的 操作元素节点 element E ...
- PowerDesigner 从数据库生成实体模型关键步骤