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、逻辑功能
在工程文件中引入
serialport
QT += 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\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软件的更多相关文章
- 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视频的英文字幕,并放到了优酷上.本文将分别对各个视频进行学习总结,提 ...
随机推荐
- 几个一看就会的实用JavaScript优雅小技巧
️ 前言 这次我就给大家分享一些一看就会的实用JavaScript优雅小技巧. 「难度:」 「推荐阅读时长:5min」 正片 减少if...else面条代码 一旦当我们写到超过两个if...else的 ...
- Python切换中英文输入法
要实现中英文切换,首先Windows系统必须要有中文语言和英文语言,才能实现输入法(语言)切换. import win32api import win32gui from win32con impor ...
- golang 指针
一个指针变量指向了一个值的内存地址,类似于变量和常量,在使用指针前你需要声明指针. 每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置.使用&字符放在变量前面对变量进行" ...
- evalJS代替mui.fire
之前一直用mui.fire调用自定义事件以达到监听目标窗口的目的. 页面为双webview,页面跳转时 mui.openWindow({ url: '../choose/food-choose-con ...
- vue组件淡入浅出动画
点击动画 hello hello world! .test-enter, .test-leave-to { opacity: 0 } .test-enter-to, .test-leave { opa ...
- 【已解决】robotframework 连接oracle数据库返回结果中文显示乱码
问题描述:查询数据库返回信息有中文的时候会显示unicode的样式,如图: 环境:robotframework 3.0.x 解决方法: 找到Python安装目录下的\Lib\site-packages ...
- 通过VS Code轻松连接树莓派
如果您正在使用树莓派作为开发平台,那么通过远程连接VS Code到树莓派是非常方便的一种方法.这样,您可以在Windows或macOS等计算机上开发和测试代码,而不必在树莓派上进行. 以下是通过VS ...
- django rest 自定义返回数据接口和异常处理
参考 Django rest framework自定义返回数据格式 一.简介 drf 默认返回的异常格式是这样的 1 { 2 "username": [ 3 "该字段是必 ...
- 学习JavaScript第四周
创建闭包的四个条件: 1.要有函数嵌套,且里层函数要操作外层函数被保护的变量. 2.返回里层函数 3.里层定义的函数要被调用,哪怕是返回一个匿名函数也行. 4.用一个变量接住,方便后续的使用. 注意: ...
- javascript原型,继承
//普通对象 //函数对象(有原型 prototy 的属性) //原型的应用 继承 function Amial(){ this.type = '小于' } function cat(name){ t ...