跳到主要内容
C++ 大前端
C++ QT 串口调试助手项目开发实战 基于 QT 框架开发的串口调试助手支持跨平台运行,具备串口搜索、参数配置、数据收发等功能。实现十六进制与文本格式转换、接收时间戳显示、定时发送及多文本区快捷指令循环发送。利用 QSerialPort 类完成底层通信,结合信号槽机制处理界面交互与定时器控制。代码结构清晰,涵盖布局管理与控件动态查找,适用于硬件调试场景参考。
编程诗人 发布于 2026/1/20 更新于 2026/6/1 20 浏览串口调试助手
一、项目概述
本项目旨在基于 QT 框架实现一款串口调试助手,帮助大家回顾 QT 项目的开发流程,以及如何使用帮助文档来进行 QT 新控件的学习。该助手具备跨平台特性,可在 Windows、Linux、macOS 等操作系统上稳定运行,满足不同开发环境下的使用需求。
从功能层面来看,这款串口调试助手涵盖了串口通信的核心需求与实用扩展功能。核心功能包括:
自动搜索并显示可用串口
支持对波特率、数据位、停止位、校验位等关键参数进行灵活配置
实现数据的实时发送与接收
扩展功能包括:
数据格式的自由转换(可在十六进制与 ASCII 码之间切换)
支持定时发送功能的精准控制
接收数据的本地记录与导出
自定义数据的快速发送
二、开发环境与工具
在本次串口调试项目开发过程中,所使用的开发环境与工具如下:
操作系统:Windows 10
QT 版本:QT 5.8.0
编译器:MinGW_32bit
开发工具:QT Creator 4.2.1(Community)
三、界面设计与布局
1.总体界面概览
如上图所示,整体上将界面分为三个部分,分别是:
上方的显示区(接收组、历史记录组、多文本组)
中间的用户交互区(参数配置区、控制区、发送区)
下方的状态栏显示区(状态、接收字节、发送字节、时间)
2.页面布局
(1)显示区
如图所示,显示区由 horizontalLayoutUp 配置为水平布局,内部承载多个功能分组与控件,整体结构可拆为 3 大核心分组(groupBoxRev、groupBoxSend、groupBoxTexts),逐层展开如下:
最外层:horizontalLayoutUp(QHBoxLayout)
作用:作为水平容器,将界面横向切分为 左、中、右 3 个功能区,让 groupBoxRev(接收区)、groupBoxSend(发送区)、groupBoxTexts(文本配置区) 水平排列,互不干扰。
第一层子控件:3 个 QGroupBox 分组
groupBoxRevQGroupBox数据接收显示区 包含 1 个 textEditRev(QTextEdit) groupBoxSendQGroupBox历史记录显示区 包含 1 个 textEditRecord(QTextEdit) groupBoxTextsQGroupBox自定义文本参数配置区 嵌套多层布局,包含按钮、标签、子布局等
以上三个分组中,groupBoxRev 和 groupBoxSend 结构简单,仅包含一个文本编辑区 QTextEdit。而 groupBoxTexts 分组较为复杂,下面我们在 UI 界面从上到下详细介绍这一分组:
horizontalLayout(QHBoxLayout)
由水平排列的 3 个 QLabel 组成:label、label_2、label_3(均为 QLabel):用于 显示说明文字(HEX、字符串、发送),无交互功能,纯 UI 引导。
verticalLayoutRealText(QVBoxLayout)
垂直排列多个 水平子布局(horizontalLayout_1 ~ horizontalLayout_9),每个子布局承载一组 '复选框 + 输入框 + 按钮' ,用于配置每组字符串编辑发送。其中每个 horizontalLayout_N(N=1~9)都是 水平子布局,结构类似,以 horizontalLayout_1 为例:checkBox_1:启用/复用 HEX 发送 lineEdit_1:快速发送的指令配置 pushButton_1:发送指令按钮
horizontalLayout_10(QHBoxLayout)
checkBox_Send(QCheckBox) : 是否启用上述指令集的循环发送(勾选后,子布局的发送逻辑生效 )
2. label_4(QLabel):说明文字(循环发送)
3. spinBox(QSpinBox):设置循环发送间隔参数
horizontalLayout_11(QHBoxLayout)
btnInit(QPushButton):初始化参数(重置上述指令配置)btnLoad(QPushButton):加载预设参数 btnSave(QPushButton):保存当前配置为文本文件
(2)用户交互区 如图所示,用户交互区由 gridLayoutDownAll 配置为网格布局,横向整合'串口参数配置'、'串口控制与数据收发辅助功能'两大板块,为串口调试的参数设置、功能操作提供交互入口,下面逐个介绍各个分组:
该部分为串口的相关配置,包括波特率、数据位、校验位、停止位和流控。其中每组由 QLabel 和 QComboBox 组成,由 QHBoxLayout 水平布局。下面以串口控件为例:布局容器:horizontalLayout_serialnum(QHBoxLayout)控件
combo_box_serialnum(MyComboBox,自定义组合框):下拉选择可用串口号,如 COM1/COM2 等,是串口连接的基础配置。
-label_5(QLabel):作为串口号选择的文本标识,显示'串口',提示用户该控件功能。
右上功能操作区——串口连接与基础操作(groupBox_DownRightUp 相关)
布局:隐含水平排列,整合串口连接、数据清理功能按钮
控件:
btnCloseOrOpenSerial(QPushButton,界面显示'打开串口'):点击触发串口的连接 / 断开操作,是串口通信的核心控制入口。
btnClearRev(对应界面'清空接收',QPushButton):一键清空接收区显示的串口数据,方便重新监测。
btnSaveRev(对应界面'保存接收',QPushButton):将接收区数据保存到本地文件,用于数据记录与分析。
checkBoxRevTime(QCheckBox,界面'接收时间'):勾选后,接收数据时附加时间戳,便于定位数据收发时序。
checkBoxHexDisplay(QCheckBox,界面'HEX 显示'):切换接收数据的显示格式,开启后以十六进制展示,适合查看二进制数据。
btnHidePanel(QPushButton,界面'隐藏面板'):点击隐藏 / 显示多文本界面区域,优化操作空间。
checkBoxAutoNewLine(QCheckBox,界面'自动换行'):控制接收数据是否自动换行显示,提升长数据阅读体验。
btnHideHistory(QPushButton,界面'隐藏历史'):隐藏 / 显示历史数据记录区域,聚焦当前操作。
右下串口发送区——数据发送控制(groupBox_DownRightLow 相关)
checkBoxSendInTime(QCheckBox,界面'定时发送'):勾选后启用定时发送功能,配合 lineEditTimeEach 实现周期性数据发送。
lineEditTimeEach(QLineEdit,界面'1000 ms / 次'):输入定时发送的时间间隔(毫秒),决定定时发送频率。
checkBoxSendNewLine(QCheckBox,界面'发送换行'):设置发送数据时是否自动附加换行符,适配接收端的数据解析需求。
checkBoxHexSend(QCheckBox,界面'HEX 发送'):切换发送数据的格式,开启后以十六进制发送,用于调试二进制指令。
btnSendContext(QPushButton,界面'发送'):点击发送 lineEditSendContext 中输入的内容,是数据发送的直接操作按钮。
lineEditSendContext(QLineEdit,界面输入框):用户输入待发送的文本 / 指令,支持手动输入、粘贴,作为串口发送的数据来源。
(3)状态显示区 由图可知,状态显示区由 widgetStatus 及子标签组成,用于展示串口通信的状态信息,使用水平布局,以下为各个控件:
labelCurrentTime(QLabel):显示当前系统时间,或配合功能展示数据收发时刻。
labelRevCnt(QLabel):统计并显示接收数据的字节数,反馈串口通信的活跃度。
labelSendCnt(QLabel):统计并显示发送数据的字节数,辅助监测发送操作。
labelSendStatus(QLabel):展示发送操作的状态(如'发送成功'/'发送失败''串口未连接'),提供反馈。
四、核心功能实现
1.串口通信核心类 QSerialPort 与 QSerialPortInfo
(1)QSerialPort
作用:QT 串口通信的核心类,封装了串口设备的打开、关闭、参数配置、数据读写等底层操作,是实现串口通信的基础。
关键用法:设置串口参数:setPortName()(串口号)、setBaudRate()(波特率)、setDataBits()(数据位)等。数据收发:write() 发送数据,readAll() 读取接收缓冲区数据。状态控制:open(QIODevice::ReadWrite) 打开串口,close() 关闭串口,isOpen() 判断是否连接。
(2)QSerialPortInfo
作用:提供串口设备的信息查询功能,用于枚举系统中可用的串口,获取串口名称、厂商信息等。
关键用法:availablePorts():返回系统中所有可用串口的列表(QList)。portName():获取串口名称(如'COM1''/dev/ttyUSB0')。
2.串口查找与打开/关闭串口
(1)查找串口 void Widget::on_comboBox_serialnum_clicked () {
ui->comboBox_serialnum->clear ();
QList<QSerialPortInfo> serialList = QSerialPortInfo::availablePorts ();
for (QSerialPortInfo serialport : serialList)
{
ui->comboBox_serialnum->addItem (serialport.portName ());
qDebug ()<<serialport.portName ();
}
ui->labelSendStatus->setText ("COM Refreshed!" );
}
主窗口刚打开时调用:因此需要在构造函数中调用该函数
Widget::Widget (QWidget *parent):QWidget (parent),ui (new Ui::Widget){
ui->setupUi (this );
on_comboBox_serialnum_clicked ();
}
用户点击串口的 comboBox 时调用:信号与槽
实现方法:由于 comboBox 没有被点击的信号可供我们直接使用,因此需要提前捕获鼠标点击事件 ,因此创建子类 MyComboBox 继承 QComboBox,并重写父类虚函数在虚函数中触发更新串口信号。
#ifndef MYCOMBOBOX_H
#define MYCOMBOBOX_H
#include <QWidget>
#include <QComboBox>
#include <QMouseEvent>
class MyComboBox :public QComboBox{
Q_OBJECT
public :
MyComboBox (QWidget *parent);
protected :
virtual void mousePressEvent (QMouseEvent *e)
{
if (e->button ()== Qt::LeftButton){
emit refresh () ;
}
QComboBox::mousePressEvent (e);
}
signals:
void refresh () ;
};
#endif
这样只需绑定信号(refresh) 与槽 (on_comboBox_serialnum_clicked) 即可:
connect (ui->comboBox_serialnum,&MyComboBox::refresh,this ,/&Widget::on_comboBox_serialnum_clicked);
(2)打开/关闭串口(on_btnCloseOrOpenSerial_clicked) 触发机制:信号与槽
功 能:该按钮有两种状态,分别为打开串口和关闭串口。
打开串口:设置 serialPort 的各自属性(如:串口名称、波特率、数据位、校验位等),调用 open 打开串口。
关闭串口:调用 close 关闭串口。
其中不同的状态对其他按钮的 enable 特性也有限制,具体见如下两张图片
如图可知,当未打开串口时,与发送特性有关的按钮无效,而像波特率、校验位等与串口有关的属性可以被选择;当串口已经打开时则相反。
void Widget::on_btnCloseOrOpenSerial_clicked () {
if (!serialStatus){
serialPort->setPortName (ui->comboBox_serialnum->currentText ());
serialPort->setBaudRate (ui->comboBox_boautrate->currentText ().toInt ());
serialPort->setDataBits (QSerialPort::DataBits (ui->comboBox_databit->currentText ().toInt ()));
switch (ui->comboBox_jiaoyan->currentIndex ()){
case 0 :
serialPort->setParity (QSerialPort::NoParity);
break ;
case 1 :
serialPort->setParity (QSerialPort::EvenParity);
break ;
case 2 :
serialPort->setParity (QSerialPort::MarkParity);
break ;
case 3 :
serialPort->setParity (QSerialPort::OddParity);
break ;
case 4 :
serialPort->setParity (QSerialPort::SpaceParity);
break ;
default :
serialPort->setParity (QSerialPort::UnknownParity);
break ;
}
switch (ui->comboBox_stopbit->currentIndex ()){
case 0 :
serialPort->setStopBits (QSerialPort::OneStop);
break ;
case 1 :
serialPort->setStopBits (QSerialPort::OneAndHalfStop);
break ;
case 2 :
serialPort->setStopBits (QSerialPort::TwoStop);
break ;
case 3 :
serialPort->setStopBits (QSerialPort::UnknownStopBits);
break ;
default :
break ;
}
if (ui->comboBox_filecon->currentText ()=="None" )
serialPort->setFlowControl (QSerialPort::NoFlowControl);
if (serialPort->open (QIODevice::ReadWrite)){
qDebug ()<<"Serial open successful!" ;
ui->comboBox_boautrate->setEnabled (false );
ui->comboBox_databit->setEnabled (false );
ui->comboBox_filecon->setEnabled (false );
ui->comboBox_jiaoyan->setEnabled (false );
ui->comboBox_serialnum->setEnabled (false );
ui->comboBox_stopbit->setEnabled (false );
ui->btnCloseOrOpenSerial->setText (tr ("关闭串口" ));
ui->btnSendContext->setEnabled (true );
ui->checkBoxSendInTime->setEnabled (true );
ui->checkBoxHexSend->setEnabled (true );
ui->checkBoxSendNewLine->setEnabled (true );
ui->labelSendStatus->setText (ui->comboBox_serialnum->currentText ()+" Open Successed!" );
serialStatus = true ;
}else {
qDebug ()<<"Serial open failed!" ;
QMessageBox::critical (this ,tr ("串口打开失败" ),tr ("打开失败,串口可能被占用或拔出!" ),QMessageBox::Ok);
}
}else {
serialPort->close ();
qDebug ()<<"Serial close successful!" ;
serialStatus = false ;
ui->comboBox_boautrate->setEnabled (true );
ui->comboBox_databit->setEnabled (true );
ui->comboBox_filecon->setEnabled (true );
ui->comboBox_jiaoyan->setEnabled (true );
ui->comboBox_serialnum->setEnabled (true );
ui->comboBox_stopbit->setEnabled (true );
ui->btnCloseOrOpenSerial->setText (tr ("打开串口" ));
ui->btnSendContext->setEnabled (false );
ui->checkBoxSendInTime->setEnabled (false );
ui->checkBoxSendInTime->setCheckState (Qt::Unchecked);
ui->lineEditTimeEach->setEnabled (true );
ui->lineEditSendContext->setEnabled (true );
ui->checkBoxHexSend->setEnabled (false );
ui->checkBoxSendNewLine->setEnabled (false );
ui->labelSendStatus->setText (ui->comboBox_serialnum->currentText ()+" Close Successed!" );
timer->stop ();
}
}
3.数据发送(on_btnSendContext_clicked)
核心逻辑:发送按照是否勾选 HEX 发送复选框来决定是 16 进制发送和文本发送。其中对于 16 进制发送会进行输入文本校验,即长度为偶数、字符合法,避免无效数据发送。
数据转换:QByteArray::fromHex()(十六进制字符串转字节流);toLocal8Bit()(文本转本地编码字节)。
发送新行:若勾选了发送新行,则会在发送内容的最后加上"\r\n"
void Widget::on_btnSendContext_clicked () {
int sendCnt = 0 ;
const char * sendMsg = ui->lineEditSendContext->text ().toLocal8Bit ().constData ();
if (ui->checkBoxHexSend->isChecked ()){
QByteArray tmp = ui->lineEditSendContext->text ().toLocal8Bit ();
if (tmp.size ()%2 !=0 ){
ui->labelSendStatus->setText ("Error Input!" );
return ;
}
for (char c : tmp){
if (!isxdigit (c)){
ui->labelSendStatus->setText ("Error Input!" );
return ;
}
}
if (ui->checkBoxSendNewLine->isChecked ()){
tmp.append ("\r\n" );
}
QByteArray sendArry = QByteArray::fromHex (tmp);
sendCnt = serialPort->write (sendArry);
}
else {
if (ui->checkBoxSendNewLine->isChecked ()){
QByteArray arrySendData (sendMsg,strlen (sendMsg));
arrySendData.append ("\r\n" );
sendCnt = serialPort->write (arrySendData);
}
else {
sendCnt = serialPort->write (sendMsg);
}
}
if (sendCnt != -1 )
{
qDebug ()<<"Send MSG:" <<sendMsg;
writeCntTotal += sendCnt;
ui->labelSendCnt->setText ("Sent:" +QString::number (writeCntTotal));
ui->labelSendStatus->setText ("Send OK!" );
if (strcmp (sendMsg,sendBak.toStdString ().c_str ())!=0 ){
ui->textEditRecord->append (sendMsg);
sendBak = QString::fromUtf8 (sendMsg);
}
}else {
ui->labelSendStatus->setText ("Send Erro!" );
}
}
4.读取数据 调用时机:函数由 QSerialPort::readyRead 信号触发,即串口有数据到达时自动执行。
connect (serialPort,&QSerialPort::readyRead,this ,&on_serialData_readyRead);
(1)自动换行 当勾选了自动换行时,会在接收数据后增加"\r\n",具体实现如下:
if (ui->checkBoxSwitchLine->isChecked ()) readMsg+="\r\n" ;
(2)HEX 显示 HEX 显示是用于帮助用于阅读二进制数据的,当勾选了 HEX 显示,接收数据时会先将当前接收区内容转换为字节数组,然后将接收字节转换为 16 进制字节数组并进行拼接,具体实现如下:
if (ui->checkBoxHexDisplay->isChecked ()){
QByteArray tmpArryHex = ui->textEditRev->toPlainText ().toUtf8 ();
QByteArray tmpHexString = tmpArryHex + readMsg.toUtf8 ().toHex ().toUpper ();
ui->textEditRev->setText (QString::fromUtf8 (tmpHexString));
}
(3)系统时间 系统时间由主窗口类中的两个成员变量组成,分别是 QTimer *sysTimer;QString myTime; 其中 sysTimer 是一个每间隔 1 秒输出一次的定时器,myTime 是用于保存当前系统时间的成员变量。
connect (sysTimer,&QTimer::timeout,this ,&Widget::on_freshTime);
sysTimer->start (100 );
void Widget::getSysTime () {
QDateTime currentTime = QDateTime::currentDateTime ();
QDate date = currentTime.date ();
QTime time = currentTime.time ();
int year = date.year ();
int month = date.month ();
int day = date.day ();
int hour = time.hour ();
int minute = time.minute ();
int second = time.second ();
myTime = QString ("%1-%2-%3 %4-%5-%6" ).arg (year,2 ,10 ,QChar ('0' )).arg (month,2 ,10 ,QChar ('0' )).arg (day,2 ,10 ,QChar ('0' )).arg (hour,2 ,10 ,QChar ('0' )).arg (minute,2 ,10 ,QChar ('0' )).arg (second,2 ,10 ,QChar ('0' ));
}
void Widget::on_freshTime () {
getSysTime ();
ui->labelCurrentTime->setText (myTime);
}
可以看到每隔一秒会刷新 myTime 变量,然后用于填充右下角的时间标签来更新系统时间。
(4)接收时间 当勾选接收时间时,会在接收数据前加入当前系统的时间,具体实现如下:
else {
if (timeDisplay){
ui->textEditRev->insertPlainText ('[' + myTime +']' +'\n' + readMsg);
}
else {
ui->textEditRev->insertPlainText (readMsg);
}
}
(5)完整代码
void Widget::on_serialData_readyRead () {
readMsg = serialPort->readAll ();
if (readMsg != NULL ){
if (ui->checkBoxSwitchLine->isChecked ()) readMsg+="\r\n" ;
if (ui->checkBoxHexDisplay->isChecked ()){
QByteArray tmpArryHex = ui->textEditRev->toPlainText ().toUtf8 ();
QByteArray tmpHexString = tmpArryHex + readMsg.toUtf8 ().toHex ().toUpper ();
ui->textEditRev->setText (QString::fromUtf8 (tmpHexString));
}
else {
if (timeDisplay){
ui->textEditRev->insertPlainText ('[' + myTime +']' +'\n' + readMsg);
}
else {
ui->textEditRev->insertPlainText (readMsg);
}
}
readCntTotal += readMsg.size ();
ui->labelRevCnt->setText ("Received:" +QString::number (readCntTotal));
ui->textEditRev->moveCursor (QTextCursor::End);
ui->textEditRev->ensureCursorVisible ();
}
qDebug ()<<"Rev MSG:" <<readMsg;
}
5.定时发送 现象:当勾选定时发送复选框时,串口会每隔 lineEditTimeEach 文本框内的时间发送一次发送框(lineEditSendContext)内的数据。
因此不难推断,当选中或取消复选框也就会启动或关闭定时器,在主窗口类中有 QTimer *timer; 成员变量,其绑定了信号与槽,当计时时间到达时会触发数据发送函数 on_btnSendContext_clicked。
connect (timer,&QTimer::timeout,this ,&Widget::on_btnSendContext_clicked);
void Widget::on_checkBoxSendInTime_clicked (bool checked) {
if (checked)
{
timer->start (ui->lineEditTimeEach->text ().toInt ());
ui->lineEditTimeEach->setEnabled (false );
ui->lineEditSendContext->setEnabled (false );
}else {
timer->stop ();
ui->lineEditTimeEach->setEnabled (true );
ui->lineEditSendContext->setEnabled (true );
}
}
6.多文本区
(1)快捷指令发送 首先我们来看一下多文本区域复选框、指令编辑框、发送按钮的命名,代码实现会利用命名特性:
从上图可以看到复选框命名为 checkBox_N、指令编辑框命名为 lineEdit_N、按钮命名为 pushButton_N,我们可以使用 QString btnName = QString("pushButton_%1").arg(i); QPushButton *btn = findChild<QPushButton *>(btnName); 来获取到每一个控件的指针。
在主窗口中,有三个成员变量 QList<QPushButton *> buttons; QList<QLineEdit *> lineEdits; QList<QCheckBox *> checkBoxs; 分别用于存储操作各个控件的指针。
在析构函数中,有如下代码来保存各个指针到列表中,同时绑定各个按钮的信号与槽
for (int i =1 ;i <=9 ;i++){
QString btnName = QString ("pushButton_%1" ).arg (i);
QPushButton *btn = findChild <QPushButton *>(btnName);
if (btn){
btn->setProperty ("btnID" ,i);
buttons.append (btn);
connect (btn,SIGNAL (clicked ()),this ,SLOT (on_command_button_clicked ()));
}
QString lineEditName = QString ("lineEdit_%1" ).arg (i);
QLineEdit *lineEdit = findChild <QLineEdit *>(lineEditName);
lineEdits.append (lineEdit);
QString checkBoxName = QString ("checkBox_%1" ).arg (i);
QCheckBox *checkBox = findChild <QCheckBox *>(checkBoxName);
checkBoxs.append (checkBox);
}
在看槽函数之前,需要了解一个函数 sender():
作用:这是 QObject 类提供的一个成员函数,返回发送当前信号的对象指针(类型为 QObject*)。
例如:当点击一个按钮时,按钮会发送 clicked() 信号,若该信号关联到某个槽函数,则在槽函数中调用 sender(),会返回这个按钮的指针。
在了解了 sender 函数的用法后,接下来看看槽函数:
void Widget::on_command_button_clicked () {
QPushButton *btn = qobject_cast <QPushButton *>(sender ());
if (btn){
int ID = btn->property ("btnID" ).toInt ();
QString checkBoxName = QString ("checkBox_%1" ).arg (ID);
QCheckBox *checkBox = findChild <QCheckBox *>(checkBoxName);
if (checkBox) ui->checkBoxHexSend->setChecked (checkBox->isChecked ());
QString lineEditName = QString ("lineEdit_%1" ).arg (ID);
QLineEdit *lineEdit = findChild <QLineEdit *>(lineEditName);
if (lineEdit )
if (lineEdit->text ().size ()<=0 ) return ;
ui->lineEditSendContext->setText (lineEdit->text ());
on_btnSendContext_clicked ();
}
}
总体而言,在多文本区中的发送指令功能,其实是调用了 on_btnSendContext_clicked 槽函数。
(2)循环发送 现象:在打开串口的前提下,当选中循环发送复选框,会以 spinBox 内设置的时间为间隔循环发送指令框中的内容(从第一个开始,到最后一个有内容的指令框截至)。
例如,在上图情况下会循环发送 1-7 文本框中的内容。我们来看具体实现:
btnCtrlTimer = new QTimer (this );
connect (btnCtrlTimer,&QTimer::timeout,this ,&Widget::btnTimeHandler);
void Widget::btnTimeHandler ()
{
qDebug ()<<"Handler" <<checkValidTextsNum ();
if (btnIndex < checkValidTextsNum ())
{
QPushButton *btnTmp = buttons[btnIndex];
emit btnTmp->clicked ();
btnIndex++;
}else {
btnIndex = 1 ;
QString checkBoxName = QString ("checkBox_1" );
QCheckBox *checkBox = findChild <QCheckBox *>(checkBoxName);
if (checkBox) ui->checkBoxHexSend->setChecked (checkBox->isChecked ());
QString lineEditName = QString ("lineEdit_1" );
QLineEdit *lineEdit = findChild <QLineEdit *>(lineEditName);
ui->lineEditSendContext->setText (lineEdit->text ());
on_btnSendContext_clicked ();
}
}
(3)checkValidTextsNum 获取有效指令数 int Widget::checkValidTextsNum () {
int num = 0 ;
for (int i =1 ;i <=9 ;i++){
QString lineEditName = QString ("lineEdit_%1" ).arg (i);
QLineEdit *lineEdit = findChild <QLineEdit *>(lineEditName);
if (!lineEdit){
qWarning ()<<"控件" << lineEditName <<"未找到!" ;
return num;
}
if (lineEdit->text ().isEmpty ())
return num;
num++;
}
return num;
}
(4)循环发送复选框 与定时发送逻辑相似,当选中复选框时启动定时器,当取消时停止定时器。
void Widget::on_checkBox_Send_clicked (bool checked) {
if (checked){
btnIndex = 0 ;
btnCtrlTimer->start (ui->spinBox->text ().toUInt ());
ui->spinBox->setEnabled (false );
}else {
btnCtrlTimer->stop ();
ui->spinBox->setEnabled (true );
}
}
六、总结 本项目基于 QT 框架实现了一款功能完善的串口调试助手,涵盖串口搜索、参数配置、数据收发等核心功能,还支持十六进制转换、定时发送、多指令循环发送等扩展功能。
开发过程中,通过 QSerialPort 与 QSerialPortInfo 类实现串口通信底层逻辑,利用布局管理器构建清晰的界面结构,将界面分为显示区、交互区和状态栏,提升了用户体验。
在功能实现上,重点解决了十六进制与文本格式转换、多控件信号处理、定时器精准控制等问题,通过动态获取控件指针实现了多指令快捷发送功能。
该项目不仅巩固了 QT 信号与槽、布局管理等基础知识,还提供了硬件调试工具开发的实践经验,为后续同类项目开发奠定了基础。
相关免费在线工具 Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
JSON 压缩 通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
JSON美化和格式化 将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online