Qt 学习笔记全系列传送门:
Qt 学习笔记 - 第二章 - 添加图片、布局、界面切换
目录
- 1、创建项目
- 2、UI
- 3、逻辑功能
- 4、程序打包和部署
1、创建项目
实现串口助手
-
基类选择 Widget
2、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、逻辑功能
-
获取串口信息并展示到页面上,在目前 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_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(; }
在工程文件中引入serialport
QT += core gui serialport
4、程序打包和部署
切换到 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>