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视频的英文字幕,并放到了优酷上.本文将分别对各个视频进行学习总结,提 ...
随机推荐
- QListWidget调用Clear时报错:ASSERT failure in QList<T>::at: "index out of range"的解决方法
原因:连接了信号currentRowChanged(int)和槽,当选中其中的一行时,在调用Clear函数就会报错. 解决方法:不连接currentRowChanged(int)信号和槽,改为连接it ...
- iOS开发之实现自定义浮动操作框效果
今天有个需求是如上图实现类似微信的自定义浮动操作框效果 我自己就写了个demo,大家感兴趣的可以试试,下面是代码 VC代码如下 #import "TestCustomMenuItemVC.h ...
- How to find WWN and WWPN of HBA card in Linux
There are several ways to detect the WWN of a Fibre Channel (FC) HBA and their details in Linux/Unix ...
- usbip:(二)从linux内核了解usb
一.前言 1.首先了解一下EHCI.UHCI和OHCI. 从硬件上来说,usb 设备要想工作,除了外设本身,必须依赖于 usb host controller.一般来说,一个电脑里有一个 usb ho ...
- 12. Redis 安装
参考http://www.runoob.com/redis/redis-install.html Window 下安装 下载地址:https://github.com/MSOpenTech/redis ...
- RN 使用react-native-video 播放视频(包含进度条、全屏)
21年12月3日,阐述上有问题:应该将问题拆分,不该将代码整一大堆,看着很不舒适 目标需求:1. 实现视频播放 2. 进度条 3. 进入全屏 目标图是这样的: 需要三个组件 1. 播放视频组件, re ...
- Luogu P2375 [NOI2014 D2]动物园 kmp
P2375 动物园 题目描述 近日,园长发现动物园中好吃懒做的动物越来越多了.例如企鹅,只会卖萌向游客要吃的.为了整治动物园的不良风气,让动物们凭自己的真才实学向游客要吃的,园长决定开设算法班,让动物 ...
- elasticsearch 根据主键_id更新部分字段
package com.better517na.ebookingbusiservice.helper;import com.alibaba.fastjson.JSON;import com.aliba ...
- Android中的特殊权限
AndroidManifest中定义的权限分为普通权限,危险权限和特殊权限. 普通权限指的是不会威胁到用户的安全和隐私的权限,只需要在AndroidManifest中声明一下就能直接使用. 危险权限指 ...
- pyahocorasick 安装和使用问题总结
因系统中用到了ahocorasick,但是程序跑起来有BUG,故而10.1假期研究了一下,趟过几个坑,分享一下. 一.安装过程中的坑 直接安装pip install pyahocorasick 是会 ...