# Qt串口调试助手 **Repository Path**: h-qilin/qt-serial-debugging-assistant ## Basic Information - **Project Name**: Qt串口调试助手 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-11-09 - **Last Updated**: 2024-11-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Qt串口调试助手 #### 串口调试助手设计UI界面 ![输入图片说明](Serial_UI001.jpg) ![输入图片说明](Serial_UI002.jpg) #### 串口调试助手自动检测串口号 QList serialList= QSerialPortInfo::availablePorts(); //获取系统中可用的串口 Widget.h ``` #ifndef WIDGET_H #define WIDGET_H #include QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: Ui::Widget *ui; }; #endif // WIDGET_H ``` Widget.cpp ``` #include "widget.h" #include "ui_widget.h" #include #include Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); this->setLayout(ui->gridLayoutGlobal); //让界面随着窗口变幻大小 QList serialList= QSerialPortInfo::availablePorts(); //获取系统中可用的串口 for(QSerialPortInfo serialInfo : serialList) //遍历所有可用串口 { qDebug() << serialInfo.portName(); ui->comboBox_serialnum->addItem(serialInfo.portName()); //将serialInfo对象所代表的串口添加到UI中 } } Widget::~Widget() { delete ui; } ``` #### 串口调试助手打开串口 Widget.h ``` #ifndef WIDGET_H #define WIDGET_H #include #include QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private slots: void on_btncloseorOpen_clicked(bool checked); //打开或关闭串口 private: QSerialPort *serialPort; Ui::Widget *ui; }; #endif // WIDGET_H ``` Widget.cpp ``` #include "widget.h" #include "ui_widget.h" #include #include #include Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); this->setLayout(ui->gridLayoutGlobal); //让界面随着窗口变幻大小 QList serialList= QSerialPortInfo::availablePorts(); //获取系统中可用的串口 for(QSerialPortInfo serialInfo : serialList) //遍历所有可用串口 { qDebug() << serialInfo.portName(); ui->comboBox_serialnum->addItem(serialInfo.portName()); //将serialInfo对象所代表的串口添加到UI中 } } Widget::~Widget() { delete ui; } void Widget::on_btncloseorOpen_clicked(bool checked) { if(!checked) { //1.选择端口号 serialPort->setPortName(ui->comboBox_serialnum->currentText()); //获取串口,把串口显示到文本上 //2.配置波特率 serialPort->setBaudRate(ui->comboBox_boautrate->currentText().toInt()); //显示波特率,转整型 //3.配置数据位 serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_databit->currentText().toInt())); //显示波特率,转整型 //4.配置校验位 switch (ui->comboBox_jiaoyan->currentText().toInt()) //用户选择校验位,并转为整型 { 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; } //5.配置停止位 serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_stopbit->currentText().toInt())); //显示停止位,转整型 //6.流控 if(ui->comboBox_fluidCon->currentText() == "None") //用户选择了None { serialPort->setFlowControl(QSerialPort::NoFlowControl); //执行,无流控 } //7.打开串口 if(serialPort->open(QIODevice::ReadWrite)) { qDebug() << "serial open success"; ui->comboBox_databit->setEnabled(false); //成功打开串口,这些按钮就失效 ui->comboBox_fluidCon->setEnabled(false); ui->comboBox_jiaoyan->setEnabled(false); ui->comboBox_stopbit->setEnabled(false); ui->comboBox_boautrate->setEnabled(false); ui->comboBox_serialnum->setEnabled(false); ui->btncloseorOpen->setText("关闭串口"); ui->btnSendContex->setEnabled(true); } else { QMessageBox msgBox; //弹窗 msgBox.setWindowTitle("打开串口错误"); msgBox.setText("打开失败,串口可能被占用"); msgBox.exec(); } } else { serialPort->close(); ui->btncloseorOpen->setText("打开串口"); ui->comboBox_databit->setEnabled(true); //没有打开串口,这些按钮都是生效的 ui->comboBox_fluidCon->setEnabled(true); ui->comboBox_jiaoyan->setEnabled(true); ui->comboBox_stopbit->setEnabled(true); ui->comboBox_boautrate->setEnabled(true); ui->comboBox_serialnum->setEnabled(true); ui->btnSendContex->setEnabled(false); } } ``` #### 串口实现自发自收功能 Widget.h ``` #ifndef WIDGET_H #define WIDGET_H #include #include QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private slots: void on_btncloseorOpen_clicked(bool checked); //打开或关闭串口 void on_btnSendContex_clicked(); //发送数据 void on_SerialData_readyToRead(); //准备去读数据 private: QSerialPort *serialPort; //声明一个对象,串口 int writeCntTotal; //统计发送了多少字节 QString SendBack; //返回上一次输入的数据 bool serialStatus; //确认状态 Ui::Widget *ui; }; #endif // WIDGET_H ``` Widgeet.cpp ``` #include "widget.h" #include "ui_widget.h" #include #include #include Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); this->setLayout(ui->gridLayoutGlobal); //让界面随着窗口变幻大小 ui->btnSendContex->setEnabled(false); //刚打开串口,发送按钮是失效的 serialPort = new QSerialPort(this); //创建一个QSerialPort对象,将指针赋值给serialPort变量 connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_SerialData_readyToRead); //连接函数,当接收数据可读时 QList serialList= QSerialPortInfo::availablePorts(); //获取系统中可用的串口 for(QSerialPortInfo serialInfo : serialList) //遍历所有可用串口 { qDebug() << serialInfo.portName(); ui->comboBox_serialnum->addItem(serialInfo.portName()); //将serialInfo对象所代表的串口添加到UI中 } } Widget::~Widget() { delete ui; } void Widget::on_btncloseorOpen_clicked(bool checked) { if(!checked) { //1.选择端口号 serialPort->setPortName(ui->comboBox_serialnum->currentText()); //获取串口,把串口显示到文本上 //2.配置波特率 serialPort->setBaudRate(ui->comboBox_boautrate->currentText().toInt()); //显示波特率,转整型 //3.配置数据位 serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_databit->currentText().toInt())); //显示波特率,转整型 //4.配置校验位 switch (ui->comboBox_jiaoyan->currentText().toInt()) //用户选择校验位,并转为整型 { 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; } //5.配置停止位 serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_stopbit->currentText().toInt())); //显示停止位,转整型 //6.流控 if(ui->comboBox_fluidCon->currentText() == "None") //用户选择了None { serialPort->setFlowControl(QSerialPort::NoFlowControl); //执行,无流控 } //7.打开串口 if(serialPort->open(QIODevice::ReadWrite)) { qDebug() << "serial open success"; ui->comboBox_databit->setEnabled(false); //成功打开串口,这些按钮就失效 ui->comboBox_fluidCon->setEnabled(false); ui->comboBox_jiaoyan->setEnabled(false); ui->comboBox_stopbit->setEnabled(false); ui->comboBox_boautrate->setEnabled(false); ui->comboBox_serialnum->setEnabled(false); ui->btncloseorOpen->setText("关闭串口"); ui->btnSendContex->setEnabled(true); } else { QMessageBox msgBox; //弹窗 msgBox.setWindowTitle("打开串口错误"); msgBox.setText("打开失败,串口可能被占用或已拔出"); msgBox.exec(); } } else { serialPort->close(); ui->btncloseorOpen->setText("打开串口"); ui->comboBox_databit->setEnabled(true); //没有打开串口,这些按钮都是生效的 ui->comboBox_fluidCon->setEnabled(true); ui->comboBox_jiaoyan->setEnabled(true); ui->comboBox_stopbit->setEnabled(true); ui->comboBox_boautrate->setEnabled(true); ui->comboBox_serialnum->setEnabled(true); serialStatus = false; ui->btnSendContex->setEnabled(false); //没有打开串口,发送按钮失效 } } void Widget::on_btnSendContex_clicked() { int writeCnt = 0; const char* sendData = ui->lineEditSendContex->text().toStdString().c_str(); //把发送文本转换为C字符串 writeCnt = serialPort->write(sendData); //返回实际写入的字节数 if(writeCnt == -1) { ui->labelSendStatus->setText("Send Error!"); //返回字节数失败,表示发送错误 } else { writeCntTotal += writeCnt; //写入成功,将字节数累加到writeCntTotal变量上 } qDebug() << "SendOK" << sendData; //输出SendOK和sendData里面的内容 ui->labelSendStatus->setText("Send OK!"); //把发送状态改为Send OK if(strcmp(sendData,SendBack.toStdString().c_str()) != 0) //比较sendData和上一次输出的数据是否相同 { ui->textEditRecord->append(sendData); //不同则在textEditRecord里追加数据 SendBack = QString(sendData); //将数据转成QString类型,以便下次使用 } } //读取发送的数据 void Widget::on_SerialData_readyToRead() { QString revMessage = serialPort->readAll(); //读取数据存于revMessage qDebug() << "getMessage:" << revMessage; ui->textEditRev->append(revMessage); //把数据显示到控件textEditRev上 } ``` #### 串口助手自动发送 Widget.h ``` #ifndef WIDGET_H #define WIDGET_H #include #include QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private slots: void on_btncloseorOpen_clicked(bool checked); //打开或关闭串口 void on_btnSendContex_clicked(); //发送数据 void on_SerialData_readyToRead(); //准备去读数据 void on_checkBoxSendInTime_clicked(bool checked); //定时发送 private: QSerialPort *serialPort; //声明一个对象,串口 int writeCntTotal; //统计发送了多少字节 int readCntTotal; //统计读取了多少字节 QString SendBack; //返回上一次输入的数据 bool serialStatus; //确认状态 QTimer *timer; //定时发送 Ui::Widget *ui; }; #endif // WIDGET_H ``` Widget.cpp ``` #include "widget.h" #include "ui_widget.h" #include #include #include #include Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); this->setLayout(ui->gridLayoutGlobal); //让界面随着窗口变幻大小 ui->btnSendContex->setEnabled(false); //刚打开串口界面,发送按钮是失效的 ui->checkBoxSendInTime->setEnabled(false); //刚打开串口界面,定时发送选择框是失效的 serialPort = new QSerialPort(this); //创建一个QSerialPort对象,将指针赋值给serialPort变量 timer = new QTimer(this); //创建一个时间对象 writeCntTotal = 0; readCntTotal = 0; connect(timer,&QTimer::timeout,this,[=](){ on_btnSendContex_clicked(); }); //连接信号与槽,到点就发送文本 connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_SerialData_readyToRead); //连接函数,当接收数据可读时 ui->comboBox_boautrate->setCurrentIndex(6); //将波特率索引值设置为6,方便选择 ui->comboBox_databit->setCurrentIndex(3); //将数据位索引值设置为3,方便选择 QList serialList= QSerialPortInfo::availablePorts(); //获取系统中可用的串口 for(QSerialPortInfo serialInfo : serialList) //遍历所有可用串口 { qDebug() << serialInfo.portName(); ui->comboBox_serialnum->addItem(serialInfo.portName()); //将serialInfo对象所代表的串口添加到UI中 } } Widget::~Widget() { delete ui; } //打开或关闭串口 void Widget::on_btncloseorOpen_clicked(bool checked) { if(!checked) { //1.选择端口号 serialPort->setPortName(ui->comboBox_serialnum->currentText()); //获取串口,把串口显示到文本上 //2.配置波特率 serialPort->setBaudRate(ui->comboBox_boautrate->currentText().toInt()); //显示波特率,转整型 //3.配置数据位 serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_databit->currentText().toInt())); //显示波特率,转整型 //4.配置校验位 switch (ui->comboBox_jiaoyan->currentText().toInt()) //用户选择校验位,并转为整型 { 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; } //5.配置停止位 serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_stopbit->currentText().toInt())); //显示停止位,转整型 //6.流控 if(ui->comboBox_fluidCon->currentText() == "None") //用户选择了None { serialPort->setFlowControl(QSerialPort::NoFlowControl); //执行,无流控 } //7.打开串口 if(serialPort->open(QIODevice::ReadWrite)) { qDebug() << "serial open success"; ui->comboBox_databit->setEnabled(false); //成功打开串口,这些按钮就失效 ui->comboBox_fluidCon->setEnabled(false); ui->comboBox_jiaoyan->setEnabled(false); ui->comboBox_stopbit->setEnabled(false); ui->comboBox_boautrate->setEnabled(false); ui->comboBox_serialnum->setEnabled(false); ui->btncloseorOpen->setText("关闭串口"); ui->btnSendContex->setEnabled(true); ui->checkBoxSendInTime->setEnabled(true); //刚打开串口界面,定时发送选择框是生效的 } else { serialPort->close(); ui->btncloseorOpen->setText("打开串口"); ui->comboBox_databit->setEnabled(true); //没有打开串口,这些按钮都是生效的 ui->comboBox_fluidCon->setEnabled(true); ui->comboBox_jiaoyan->setEnabled(true); ui->comboBox_stopbit->setEnabled(true); ui->comboBox_boautrate->setEnabled(true); ui->comboBox_serialnum->setEnabled(true); //serialStatus = false; ui->btnSendContex->setEnabled(false); //没有打开串口,发送按钮失效 ui->checkBoxSendInTime->setEnabled(false); //打开串口失败,定时发送按钮失效 ui->checkBoxSendInTime->setCheckState(Qt::Unchecked); timer->stop(); ui->lineEditTimeeach->setEnabled(true); ui->lineEditSendContex->setEnabled(true); } } else { qDebug() << "error"; QMessageBox msgBox; //弹窗 msgBox.setWindowTitle("打开串口错误"); msgBox.setText("打开失败,串口可能被占用或已拔出"); msgBox.exec(); } } //发送数据 void Widget::on_btnSendContex_clicked() { int writeCnt = 0; const char* sendData = ui->lineEditSendContex->text().toLocal8Bit().constData(); //把发送文本转换为C字符串指针 writeCnt = serialPort->write(sendData); //返回实际写入的字节数 if(writeCnt == -1) { ui->labelSendStatus->setText("Send Error!"); //返回字节数失败,表示发送错误 } else { writeCntTotal += writeCnt; //写入成功,将字节数累加到writeCntTotal变量上 qDebug() << "SendOK" << sendData; //输出SendOK和sendData里面的内容 ui->labelSendStatus->setText("Send OK!"); //把发送状态改为Send OK ui->labelSendcnt->setNum(writeCntTotal); //计算发送字节数 if(strcmp(sendData,SendBack.toStdString().c_str()) != 0) //比较sendData和上一次输出的数据是否相同 { ui->textEditRecord->append(sendData); //不同则在textEditRecord里追加数据 SendBack = QString::fromUtf8(sendData); //将数据转成QString类型,以便下次使用 } } } //读取发送的数据 void Widget::on_SerialData_readyToRead() { QString revMessage = serialPort->readAll(); //读取数据存于revMessage if(revMessage != NULL) //检查指针 revMessage 是否为非空指针 { qDebug() << "getMessage:" << revMessage; //打印接收的内容 ui->textEditRev->append(revMessage); //将收到的内容追加到textEditRev文本框中 readCntTotal += revMessage.size(); ui->labelRevcnt->setNum(readCntTotal); //计算接收到的字节数 } } //自动发送 void Widget::on_checkBoxSendInTime_clicked(bool checked) { // qDebug() <<"checkBsendIntime" << checked; if(checked) //检测复选框是否被选中 { ui->lineEditTimeeach->setEnabled(false); //定时发送开始,定时文本无效 ui->lineEditTimeeach->setEnabled(false); //定时发送开始,发送文本无效 timer->start(1000); //启动定时器 timer->start(ui->lineEditTimeeach->text().toInt()); //允许用户修改时间间隔 //on_btnSendContex_clicked(); } else { timer->stop(); //停止定时器 ui->lineEditTimeeach->setEnabled(true); //定时器停止后,定时文本变有效 ui->lineEditSendContex->setEnabled(true); //定时器停止后,发送文本变有效 } } ``` #### 保存串口接收的内容 Widget.h ``` #ifndef WIDGET_H #define WIDGET_H #include #include QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private slots: void on_btncloseorOpen_clicked(bool checked); //打开或关闭串口 void on_btnSendContex_clicked(); //发送数据 void on_SerialData_readyToRead(); //准备去读数据 void on_checkBoxSendInTime_clicked(bool checked); //定时发送 void on_btnrevClear_clicked(); void on_btnrevSave_clicked(); private: QSerialPort *serialPort; //声明一个对象,串口 int writeCntTotal; //统计发送了多少字节 int readCntTotal; //统计发送了多少字节 QString SendBack; //返回上一次输入的数据 bool serialStatus; //确认状态 QTimer *timer; //定时发送 Ui::Widget *ui; }; #endif // WIDGET_H ``` Widget.cpp ``` #include "widget.h" #include "ui_widget.h" #include #include #include #include #include Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); this->setLayout(ui->gridLayoutGlobal); //让界面随着窗口变幻大小 ui->btnSendContex->setEnabled(false); //刚打开串口,发送按钮是失效的 ui->checkBoxSendInTime->setEnabled(false); //刚打开串口界面,定时发送选择框是失效的 serialPort = new QSerialPort(this); //创建一个QSerialPort对象,将指针赋值给serialPort变量 timer = new QTimer(this); //创建一个时间对象 writeCntTotal = 0; readCntTotal = 0; connect(timer,&QTimer::timeout,this,[=](){ on_btnSendContex_clicked(); }); //连接信号与槽,到点就发送文本 connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_SerialData_readyToRead); //连接函数,当接收数据可读时 ui->comboBox_boautrate->setCurrentIndex(6); //将波特率索引值设置为6,方便选择 ui->comboBox_databit->setCurrentIndex(3); //将数据位索引值设置为3,方便选择 QList serialList= QSerialPortInfo::availablePorts(); //获取系统中可用的串口 for(QSerialPortInfo serialInfo : serialList) //遍历所有可用串口 { qDebug() << serialInfo.portName(); ui->comboBox_serialnum->addItem(serialInfo.portName()); //将serialInfo对象所代表的串口添加到UI中 } } Widget::~Widget() { delete ui; } void Widget::on_btncloseorOpen_clicked(bool checked) { if(checked) { //1.选择端口号 serialPort->setPortName(ui->comboBox_serialnum->currentText()); //获取串口,把串口显示到文本上 //2.配置波特率 serialPort->setBaudRate(ui->comboBox_boautrate->currentText().toInt()); //显示波特率,转整型 //3.配置数据位 serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_databit->currentText().toInt())); //显示波特率,转整型 //4.配置校验位 switch (ui->comboBox_jiaoyan->currentText().toInt()) //用户选择校验位,并转为整型 { 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; } //5.配置停止位 serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_stopbit->currentText().toInt())); //显示停止位,转整型 //6.流控 if(ui->comboBox_fluidCon->currentText() == "None") //用户选择了None { serialPort->setFlowControl(QSerialPort::NoFlowControl); //执行,无流控 } //7.打开串口 if(serialPort->open(QIODevice::ReadWrite)) { qDebug() << "serial open success"; ui->comboBox_databit->setEnabled(false); //成功打开串口,这些按钮就失效 ui->comboBox_fluidCon->setEnabled(false); ui->comboBox_jiaoyan->setEnabled(false); ui->comboBox_stopbit->setEnabled(false); ui->comboBox_boautrate->setEnabled(false); ui->comboBox_serialnum->setEnabled(false); ui->btncloseorOpen->setText("关闭串口"); ui->btnSendContex->setEnabled(true); } else { qDebug() << "error"; QMessageBox msgBox; //弹窗 msgBox.setWindowTitle("打开串口错误"); msgBox.setText("打开失败,串口可能被占用或已拔出"); msgBox.exec(); } } else { serialPort->close(); ui->btncloseorOpen->setText("打开串口"); ui->comboBox_databit->setEnabled(true); //没有打开串口,这些按钮都是生效的 ui->comboBox_fluidCon->setEnabled(true); ui->comboBox_jiaoyan->setEnabled(true); ui->comboBox_stopbit->setEnabled(true); ui->comboBox_boautrate->setEnabled(true); ui->comboBox_serialnum->setEnabled(true); //serialStatus = false; ui->btnSendContex->setEnabled(false); //没有打开串口,发送按钮失效 ui->checkBoxSendInTime->setEnabled(false); //打开串口失败,定时发送按钮失效 ui->checkBoxSendInTime->setCheckState(Qt::Unchecked); timer->stop(); ui->lineEditTimeeach->setEnabled(true); ui->lineEditSendContex->setEnabled(true); } } //发送数据 void Widget::on_btnSendContex_clicked() { int writeCnt = 0; const char* sendData = ui->lineEditSendContex->text().toLocal8Bit().constData(); //把发送文本转换为C字符串指针 writeCnt = serialPort->write(sendData); //返回实际写入的字节数 if(writeCnt == -1) { ui->labelSendStatus->setText("Send Error!"); //返回字节数失败,表示发送错误 } else { writeCntTotal += writeCnt; //写入成功,将字节数累加到writeCntTotal变量上 qDebug() << "SendOK" << sendData; //输出SendOK和sendData里面的内容 ui->labelSendStatus->setText("Send OK!"); //把发送状态改为Send OK ui->labelSendcnt->setNum(writeCntTotal); if(strcmp(sendData,SendBack.toStdString().c_str()) != 0) //比较sendData和上一次输出的数据是否相同 { ui->textEditRecord->append(sendData); //不同则在textEditRecord里追加数据 SendBack = QString::fromUtf8(sendData); //将数据转成QString类型,以便下次使用 } } } //读取发送的数据 void Widget::on_SerialData_readyToRead() { QString revMessage = serialPort->readAll(); //读取数据存于revMessage if(revMessage != NULL) { qDebug() << "getMessage:" << revMessage; ui->textEditRev->append(revMessage); readCntTotal += revMessage.size(); ui->labelRevcnt->setNum(readCntTotal); } } //自动发送 void Widget::on_checkBoxSendInTime_clicked(bool checked) { // qDebug() <<"checkBsendIntime" << checked; if(checked) //检测复选框是否被选中 { ui->lineEditTimeeach->setEnabled(false); //定时发送开始,定时文本无效 ui->lineEditTimeeach->setEnabled(false); //定时发送开始,发送文本无效 timer->start(1000); //启动定时器 timer->start(ui->lineEditTimeeach->text().toInt()); //允许用户修改时间间隔 //on_btnSendContex_clicked(); } else { timer->stop(); //停止定时器 ui->lineEditTimeeach->setEnabled(true); //定时器停止后,定时文本变有效 ui->lineEditSendContex->setEnabled(true); //定时器停止后,发送文本变有效 } } //清空接收 void Widget::on_btnrevClear_clicked() { ui->textEditRev->setText(""); //清空接收内容 } //保存接收内容 void Widget::on_btnrevSave_clicked() { QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "L:/QTproject/QT/serialData.txt", tr("Text (*.txt)")); //弹出文件选择框,保存文件 if(fileName != NULL) { QFile file(fileName); //创建一个 QFile 对象,用于操作文件 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return; //打开文件失败,则直接返回 } QTextStream out(&file); //创建一个QTextStream 对象,用于将数据写入文件 out <textEditRev->toPlainText(); //获取文本内容,输出到流out file.close(); //关闭文件 } } ``` #### 串口调试助手Hex发送和Hex显示 Widget.h ``` #ifndef WIDGET_H #define WIDGET_H #include #include QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private slots: void on_btncloseorOpen_clicked(bool checked); //打开或关闭串口 void on_btnSendContex_clicked(); //发送数据 void on_SerialData_readyToRead(); //准备去读数据 void on_checkBoxSendInTime_clicked(bool checked); //定时发送 void on_btnrevClear_clicked(); //接收清楚 void on_btnrevSave_clicked(); //保存接收 void time_reflash(); //更新系统时间 void on_checkBoxHexDisplay_clicked(bool checked); //Hex显示 private: QSerialPort *serialPort; //声明一个对象,串口 int writeCntTotal; //统计发送了多少字节 int readCntTotal; //统计发送了多少字节 QString SendBack; //返回上一次输入的数据 QString MyTime; //系统时间 bool serialStatus; //确认状态 QTimer *timer; //定时发送 void getSysTime(); //获取系统时间 Ui::Widget *ui; }; #endif // WIDGET_H ``` Widget.cpp ``` #include "widget.h" #include "ui_widget.h" #include #include #include #include #include #include Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); this->setLayout(ui->gridLayoutGlobal); //让界面随着窗口变幻大小 ui->btnSendContex->setEnabled(false); //刚打开串口,发送按钮是失效的 ui->checkBoxSendInTime->setEnabled(false); //刚打开串口界面,定时发送选择框是失效的 ui->checkBoxrevTime->setEnabled(false); //刚打开串口界面,接收时间选择框是失效的 serialPort = new QSerialPort(this); //创建一个QSerialPort对象,将指针赋值给serialPort变量 QTimer *getSysTimeTimer = new QTimer(this); //创建一个QTimer对象,将指针赋值给getSysTimeTimer connect(getSysTimeTimer,SIGNAL(timeout()),this,SLOT(time_reflash())); getSysTimeTimer->start(100); //启动定时器,每隔100毫秒触发一次timeout信号 timer = new QTimer(this); //创建一个时间对象 writeCntTotal = 0; readCntTotal = 0; connect(timer,&QTimer::timeout,this,[=](){ on_btnSendContex_clicked(); }); //连接信号与槽,到点就发送文本 connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_SerialData_readyToRead); //连接函数,当接收数据可读时 ui->comboBox_boautrate->setCurrentIndex(6); //将波特率索引值设置为6,方便选择 ui->comboBox_databit->setCurrentIndex(3); //将数据位索引值设置为3,方便选择 QList serialList= QSerialPortInfo::availablePorts(); //获取系统中可用的串口 for(QSerialPortInfo serialInfo : serialList) //遍历所有可用串口 { qDebug() << serialInfo.portName(); ui->comboBox_serialnum->addItem(serialInfo.portName()); //将serialInfo对象所代表的串口添加到UI中 } } Widget::~Widget() { delete ui; } void Widget::on_btncloseorOpen_clicked(bool checked) { if(checked) { //1.选择端口号 serialPort->setPortName(ui->comboBox_serialnum->currentText()); //获取串口,把串口显示到文本上 //2.配置波特率 serialPort->setBaudRate(ui->comboBox_boautrate->currentText().toInt()); //显示波特率,转整型 //3.配置数据位 serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_databit->currentText().toInt())); //显示波特率,转整型 //4.配置校验位 switch (ui->comboBox_jiaoyan->currentText().toInt()) //用户选择校验位,并转为整型 { 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; } //5.配置停止位 serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_stopbit->currentText().toInt())); //显示停止位,转整型 //6.流控 if(ui->comboBox_fluidCon->currentText() == "None") //用户选择了None { serialPort->setFlowControl(QSerialPort::NoFlowControl); //执行,无流控 } //7.打开串口 if(serialPort->open(QIODevice::ReadWrite)) { qDebug() << "serial open success"; ui->comboBox_databit->setEnabled(false); //成功打开串口,这些按钮就失效 ui->comboBox_fluidCon->setEnabled(false); ui->comboBox_jiaoyan->setEnabled(false); ui->comboBox_stopbit->setEnabled(false); ui->comboBox_boautrate->setEnabled(false); ui->comboBox_serialnum->setEnabled(false); ui->btncloseorOpen->setText("关闭串口"); ui->btnSendContex->setEnabled(true); ui->checkBoxSendInTime->setEnabled(true); //成功打开串口,定时发送按钮生效 ui->checkBoxrevTime->setEnabled(true); //成功打开串口,接收时间按钮生效 } else { qDebug() << "error"; QMessageBox msgBox; //弹窗 msgBox.setWindowTitle("打开串口错误"); msgBox.setText("打开失败,串口可能被占用或已拔出"); msgBox.exec(); } } else { serialPort->close(); ui->btncloseorOpen->setText("打开串口"); ui->comboBox_databit->setEnabled(true); //没有打开串口,这些按钮都是生效的 ui->comboBox_fluidCon->setEnabled(true); ui->comboBox_jiaoyan->setEnabled(true); ui->comboBox_stopbit->setEnabled(true); ui->comboBox_boautrate->setEnabled(true); ui->comboBox_serialnum->setEnabled(true); //serialStatus = false; ui->btnSendContex->setEnabled(false); //没有打开串口,发送按钮失效 ui->checkBoxSendInTime->setEnabled(false); //打开串口失败,定时发送按钮失效 ui->checkBoxSendInTime->setCheckState(Qt::Unchecked); //设置复选框为未选中状态 timer->stop(); ui->lineEditTimeeach->setEnabled(true); ui->lineEditSendContex->setEnabled(true); } } //发送数据 void Widget::on_btnSendContex_clicked() { int writeCnt = 0; const char* sendData = ui->lineEditSendContex->text().toLocal8Bit().constData(); //把发送文本转换为C字符串指针 if(ui->checkBHexSend->isChecked()) //判断按键是否被按下 { QString tmp = ui->lineEditSendContex->text().toLocal8Bit().constData(); //判断是否是偶数位,16进制是两位 QByteArray tmpArray = tmp.toLocal8Bit(); if(tmpArray.size() % 2 != 0) { ui->labelSendStatus->setText("Error Input"); } //判断是否符合16进制的表达 for(char c : tmpArray) //定义一个c,遍历tmpArray数组 { if(!std::isxdigit(c)) //判断每一位是不是十六进制 { ui->labelSendStatus->setText("Error Input"); return; } } //转换成16进制发送,用户输入1,变成1,不会变成字符1,ASCII码 QByteArray arraySend = QByteArray::fromHex(tmpArray); //发送16进制 writeCnt = serialPort->write(arraySend); //返回实际写入的字节数 } else { writeCnt = serialPort->write(sendData); //返回实际写入的字节数 } if(writeCnt == -1) { ui->labelSendStatus->setText("Send Error!"); //返回字节数失败,表示发送错误 } else { writeCntTotal += writeCnt; //写入成功,将字节数累加到writeCntTotal变量上 qDebug() << "SendOK" << sendData; //输出SendOK和sendData里面的内容 ui->labelSendStatus->setText("Send OK!"); //把发送状态改为Send OK ui->labelSendcnt->setNum(writeCntTotal); if(strcmp(sendData,SendBack.toStdString().c_str()) != 0) //比较sendData和上一次输出的数据是否相同 { ui->textEditRecord->append(sendData); //不同则在textEditRecord里追加数据 SendBack = QString::fromUtf8(sendData); //将数据转成QString类型,以便下次使用 } } } //读取发送的数据 void Widget::on_SerialData_readyToRead() { QString revMessage = serialPort->readAll(); //读取数据存于revMessage if(revMessage != NULL) //检查指针 revMessage 是否为非空指针,读取数据不为空 { if(ui->checkBoxHexDisplay->isChecked()) //判断Hex显示是否被勾选 { QByteArray tmpHexString = revMessage.toUtf8().toHex(); //原来控件上的内容,hex QString tmpStringHex = ui->textEditRev->toPlainText(); //因为勾选了,读出来就是Hex tmpHexString = tmpStringHex.toUtf8() + tmpHexString; //把读出的就的hex和新收到的数据转成hex进行拼接 ui->textEditRev->setText(QString::fromUtf8(tmpHexString)); //重新显示在控件上 } else { if(ui->checkBoxrevTime->isChecked()) { getSysTime(); QString message = ui->lineEditSendContex->text() + " " + "【"+MyTime+"】"; ui->textEditRev->append(message); } else { ui->textEditRev->append(revMessage); //将收到的内容追加到textEditRev文本框中 } } readCntTotal += revMessage.size(); ui->labelRevcnt->setNum(readCntTotal); //计算接收到的字节数 } } //自动发送 void Widget::on_checkBoxSendInTime_clicked(bool checked) { // qDebug() <<"checkBsendIntime" << checked; if(checked) //检测复选框是否被选中 { ui->lineEditTimeeach->setEnabled(false); //定时发送开始,定时文本无效 ui->lineEditTimeeach->setEnabled(false); //定时发送开始,发送文本无效 timer->start(1000); //启动定时器 timer->start(ui->lineEditTimeeach->text().toInt()); //允许用户修改时间间隔 //on_btnSendContex_clicked(); } else { timer->stop(); //停止定时器 ui->lineEditTimeeach->setEnabled(true); //定时器停止后,定时文本变有效 ui->lineEditSendContex->setEnabled(true); //定时器停止后,发送文本变有效 } } //清空接收 void Widget::on_btnrevClear_clicked() { ui->textEditRev->setText(""); //清空接收内容 } //保存接收内容 void Widget::on_btnrevSave_clicked() { QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "L:/QTproject/QT/serialData.txt", tr("Text (*.txt)")); //弹出文件选择框,保存文件 if(fileName != NULL) { QFile file(fileName); //创建一个 QFile 对象,用于操作文件 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return; //打开文件失败,则直接返回 } QTextStream out(&file); //创建一个QTextStream 对象,用于将数据写入文件 out <textEditRev->toPlainText(); //获取文本内容,输出到流out file.close(); //关闭文件 } } //更新串口调试助手时间 void Widget::time_reflash() { getSysTime(); ui->labelCurrentTime->setText(MyTime); } //获取系统时间 void Widget::getSysTime() { QDateTime currentTime = QDateTime::currentDateTime(); //创建一个currentTime对象,返回当前系统时间 QDate date = currentTime.date(); //返回一个日期对象date int year = date.year(); //获取年份,存储在year变量中 int month = date.month(); //获取月份,存储在month变量中 int day = date.day(); //获取日,存储在day变量中 QTime time = currentTime.time(); //创建一个time对象,返回时间 int hour = time.hour(); //获取时,存储在hour变量中 int minute = time.minute(); //获取时,存储在minute变量中 int second = time.second(); //获取时,存储在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')); } //Hex显示 void Widget::on_checkBoxHexDisplay_clicked(bool checked) { if(checked) //如果打勾 { //1.读取textEdit内容 QString tmp = ui->textEditRev->toPlainText(); //2.转换成hex(因为QByteArray有toHex(),所以转换成QByteArray) QByteArray qtmp = tmp.toUtf8(); //因为QSrting没有把小写字母a转化成61的能力,QByteArray有,所以用QByteArray qtmp = qtmp.toHex(); //3.显示 QString lastShow; tmp = QString::fromUtf8(qtmp); //把QByteArray转换成QString格式 for(int i = 0; itextEditRev->setText(lastShow.toUpper()); //转换成大写 } else { //1.读取textEdit内容,hex QString tmpHexString = ui->textEditRev->toPlainText(); //2.将 QString 转换为 QByteArray QByteArray tmpHexQBytearray = tmpHexString.toUtf8(); //3.将十六进制字符串转换为字节数组 QByteArray tmpQByteString = QByteArray::fromHex(tmpHexQBytearray); //将61转换成a //4.显示 ui->textEditRev->setText(QString::fromUtf8(tmpQByteString)); } } ``` #### 串口调试助手自动换行和发送新行 Widget.h ``` #ifndef WIDGET_H #define WIDGET_H #include #include QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private slots: void on_btncloseorOpen_clicked(bool checked); //打开或关闭串口 void on_btnSendContex_clicked(); //发送数据 void on_SerialData_readyToRead(); //准备去读数据 void on_checkBoxSendInTime_clicked(bool checked); //定时发送 void on_btnrevClear_clicked(); //接收清楚 void on_btnrevSave_clicked(); //保存接收 void time_reflash(); //更新系统时间 void on_checkBoxHexDisplay_clicked(bool checked); //Hex显示 private: QSerialPort *serialPort; //声明一个对象,串口 int writeCntTotal; //统计发送了多少字节 int readCntTotal; //统计发送了多少字节 QString SendBack; //返回上一次输入的数据 QString MyTime; //系统时间 bool serialStatus; //确认状态 QTimer *timer; //定时发送 void getSysTime(); //获取系统时间 Ui::Widget *ui; }; #endif // WIDGET_H ``` Widget.cpp ``` #include "widget.h" #include "ui_widget.h" #include #include #include #include #include #include Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); this->setLayout(ui->gridLayoutGlobal); //让界面随着窗口变幻大小 ui->btnSendContex->setEnabled(false); //刚打开串口,发送按钮是失效的 ui->checkBoxSendInTime->setEnabled(false); //刚打开串口界面,定时发送选择框是失效的 ui->checkBoxrevTime->setEnabled(false); //刚打开串口界面,接收时间选择框是失效的 serialPort = new QSerialPort(this); //创建一个QSerialPort对象,将指针赋值给serialPort变量 QTimer *getSysTimeTimer = new QTimer(this); //创建一个QTimer对象,将指针赋值给getSysTimeTimer connect(getSysTimeTimer,SIGNAL(timeout()),this,SLOT(time_reflash())); getSysTimeTimer->start(100); //启动定时器,每隔100毫秒触发一次timeout信号 timer = new QTimer(this); //创建一个时间对象 //控制参数初始化 writeCntTotal = 0; //写入字节数 readCntTotal = 0; //读取字节数 serialStatus = false; //失效状态 //控件初始化 ui->btnSendContex->setEnabled(false); //发送按钮失效 ui->checkBoxSendInTime->setEnabled(false); //定时发送按钮失效 ui->checkSendNewLine->setEnabled(false); //发送新行失效 ui->checkBHexSend->setEnabled(false); //HEX发送失效 connect(timer,&QTimer::timeout,this,[=](){ on_btnSendContex_clicked(); }); //连接信号与槽,到点就发送文本 connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_SerialData_readyToRead); //连接函数,当接收数据可读时 ui->comboBox_boautrate->setCurrentIndex(6); //将波特率索引值设置为6,方便选择 ui->comboBox_databit->setCurrentIndex(3); //将数据位索引值设置为3,方便选择 QList serialList= QSerialPortInfo::availablePorts(); //获取系统中可用的串口 for(QSerialPortInfo serialInfo : serialList) //遍历所有可用串口 { qDebug() << serialInfo.portName(); ui->comboBox_serialnum->addItem(serialInfo.portName()); //将serialInfo对象所代表的串口添加到UI中 } ui->labelSendStatus->setText(ui->comboBox_serialnum->itemText(0)+" " + "NoOpen"); //状态文本初始化 } Widget::~Widget() { delete ui; } //打开或关闭串口 void Widget::on_btncloseorOpen_clicked(bool checked) { if(checked) { //1.选择端口号 serialPort->setPortName(ui->comboBox_serialnum->currentText()); //获取串口,把串口显示到文本上 //2.配置波特率 serialPort->setBaudRate(ui->comboBox_boautrate->currentText().toInt()); //显示波特率,转整型 //3.配置数据位 serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_databit->currentText().toInt())); //显示波特率,转整型 //4.配置校验位 switch (ui->comboBox_jiaoyan->currentText().toInt()) //用户选择校验位,并转为整型 { 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; } //5.配置停止位 serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_stopbit->currentText().toInt())); //显示停止位,转整型 //6.流控 if(ui->comboBox_fluidCon->currentText() == "None") //用户选择了None { serialPort->setFlowControl(QSerialPort::NoFlowControl); //执行,无流控 } //7.打开串口 if(serialPort->open(QIODevice::ReadWrite)) { qDebug() << "serial open success"; ui->comboBox_databit->setEnabled(false); //成功打开串口,这些按钮就失效 ui->comboBox_fluidCon->setEnabled(false); ui->comboBox_jiaoyan->setEnabled(false); ui->comboBox_stopbit->setEnabled(false); ui->comboBox_boautrate->setEnabled(false); ui->comboBox_serialnum->setEnabled(false); ui->btncloseorOpen->setText("关闭串口"); ui->btnSendContex->setEnabled(true); //成功打开串口,发送文本按钮生效 ui->checkBoxSendInTime->setEnabled(true); //成功打开串口,定时发送按钮生效 ui->checkSendNewLine->setEnabled(true); //发送新行生效 ui->checkBHexSend->setEnabled(true); //HEX发送生效 ui->labelSendStatus->setText(ui->comboBox_serialnum->currentText() + " " + "isOpen"); } else { qDebug() << "error"; QMessageBox msgBox; //弹窗 msgBox.setWindowTitle("打开串口错误"); msgBox.setText("打开失败,串口可能被占用或已拔出"); msgBox.exec(); } } else { serialPort->close(); ui->btncloseorOpen->setText("打开串口"); ui->comboBox_databit->setEnabled(true); //没有打开串口,这些按钮都是生效的 ui->comboBox_fluidCon->setEnabled(true); ui->comboBox_jiaoyan->setEnabled(true); ui->comboBox_stopbit->setEnabled(true); ui->comboBox_boautrate->setEnabled(true); ui->comboBox_serialnum->setEnabled(true); //serialStatus = false; ui->btnSendContex->setEnabled(false); //没有打开串口,发送按钮失效 ui->checkBoxSendInTime->setEnabled(false); //打开串口失败,定时发送按钮失效 ui->checkBoxSendInTime->setCheckState(Qt::Unchecked); //设置复选框为未选中状态 //关闭定时器 timer->stop(); ui->lineEditTimeeach->setEnabled(true); //没有打开串口,时间修改生效 ui->lineEditSendContex->setEnabled(true); //没有打开串口,发送文本生效 ui->checkSendNewLine->setEnabled(false); //发送新行失效 ui->checkBHexSend->setEnabled(false); //HEX发送失效 ui->labelSendStatus->setText(ui->comboBox_serialnum->currentText() + " " + "isClose"); } } //发送数据 void Widget::on_btnSendContex_clicked() { int writeCnt = 0; //写入字节数 const char* sendData = ui->lineEditSendContex->text().toLocal8Bit().constData(); //把发送文本转换为C字符串指针 if(ui->checkBHexSend->isChecked()) //判断按键是否被按下,是否16进制发送 { QString tmp = ui->lineEditSendContex->text().toLocal8Bit().constData(); // 获取文本框中的内容,并转换为本地8位编码的C字符串 QByteArray tmpArray = tmp.toLocal8Bit(); // 将QString再次转换为QByteArray,这里实际上tmp已经是QByteArray类型了 //判断是否是偶数位,16进制是两位 if(tmpArray.size() % 2 != 0) { ui->labelSendStatus->setText("Error Input"); } //判断是否符合16进制的表达 for(char c : tmpArray) //定义一个c,遍历tmpArray数组 { if(!std::isxdigit(c)) //判断每一位是不是十六进制 { ui->labelSendStatus->setText("Error Input"); //不是偶数,则设置状态标签显示错误信息 return; } } if(ui->checkSendNewLine->isChecked()) //如果勾选发送新行 { tmpArray.append("\r\n"); //在数据末尾添加回车换行符 //转换成16进制发送,用户输入1,变成1,不会变成字符1,ASCII码 QByteArray arraySend = QByteArray::fromHex(tmpArray); //发送16进制,将十六进制字符串转换为实际的数据 writeCnt = serialPort->write(arraySend); //记录发送字节数 } } //按键没被勾选,不是16进制发送 else { //判断发送新行是否勾选 if(ui->checkSendNewLine->isChecked()) { QByteArray arraySendData(sendData,strlen(sendData)); // 创建一个QByteArray对象,包含sendData的内容 arraySendData.append("\r\n"); //在数据末尾添加回车换行符 writeCnt = serialPort->write(arraySendData); //返回实际写入的字节数 } else { writeCnt = serialPort->write(sendData); //没有勾选发送新行,返回实际写入的字节数 } } //发送失败清空 if(writeCnt == -1) { ui->labelSendStatus->setText("Send Error!"); //返回字节数失败,表示发送错误 } else { writeCntTotal += writeCnt; //写入成功,将字节数累加到writeCntTotal变量上 qDebug() << "SendOK" << sendData; //输出SendOK和sendData里面的内容 ui->labelSendStatus->setText("Send OK!"); //把发送状态改为Send OK ui->labelSendcnt->setNum(writeCntTotal); // 更新显示已发送的总字节数 if(strcmp(sendData,SendBack.toStdString().c_str()) != 0) //比较sendData和上一次输出的数据是否相同,SendBack转换为C风格字符串 { ui->textEditRecord->append(sendData); //不同则在textEditRecord里追加数据 SendBack = QString::fromUtf8(sendData); //将数据转成QString类型,以便下次使用 } } } //读取发送的数据 void Widget::on_SerialData_readyToRead() { QString revMessage = serialPort->readAll(); //读取数据存于revMessage if(revMessage != NULL) //检查指针 revMessage 是否为非空指针,读取数据不为空 { if(ui->checkBLine->isChecked()) { revMessage.append("\r\n"); //如果选中了自动换行复选框,则在数据末尾添加回车换行符 } //16进制显示 if(ui->checkBoxHexDisplay->isChecked()) //判断Hex显示是否被勾选 { QByteArray tmpHexString = revMessage.toUtf8().toHex().toUpper(); // 将接收到的数据转换为16进制字符串并转为大写 //原来控件上的内容,hex QString tmpStringHex = ui->textEditRev->toPlainText(); //因为勾选了,读出来就是Hex tmpHexString = tmpStringHex.toUtf8() + tmpHexString; //把读出的就的hex和新收到的数据转成hex进行拼接 ui->textEditRev->setText(QString::fromUtf8(tmpHexString)); //重新显示在控件上 } //非十六进制显示 else { //是否选中发送新行 if(ui->checkSendNewLine->isChecked()) { revMessage.append("\r\n"); //如果选中了“添加新行”复选框,则在数据末尾添加回车换行符 } //勾选发送时间 if(ui->checkBoxrevTime->isChecked()) { getSysTime(); //获取系统时间 QString message = ui->lineEditSendContex->text() + " " + "【"+MyTime+"】"; //构造带有时间戳的消息 ui->textEditRev->insertPlainText(message); //将消息插入到文本编辑框中 } else { ui->textEditRev->insertPlainText(revMessage); //当前光标位置插入内容,不会清除文本 } } } readCntTotal += revMessage.size(); //接收的总字节数 ui->labelRevcnt->setNum(readCntTotal); //计算接收到的字节数 } //自动发送 void Widget::on_checkBoxSendInTime_clicked(bool checked) { if(checked) //检测复选框是否被选中 { ui->lineEditTimeeach->setEnabled(false); //定时发送开始,定时发送文本无效 ui->lineEditSendContex->setEnabled(false); //定时发送开始,发送文本无效 timer->start(1000); //启动定时器,初始间隔为1秒 timer->start(ui->lineEditTimeeach->text().toInt()); //允许用户修改时间间隔 } else { timer->stop(); //停止定时器 ui->lineEditTimeeach->setEnabled(true); //定时器停止后,定时文本变有效 ui->lineEditSendContex->setEnabled(true); //定时器停止后,发送文本变有效 } } //清空接收 void Widget::on_btnrevClear_clicked() { ui->textEditRev->setText(""); //清空接收内容 } //保存接收内容 void Widget::on_btnrevSave_clicked() { QString fileName = QFileDialog::getSaveFileName(this, tr("保存文件"), "L:/QTproject/QT/serialData.txt", tr("文件类型 (*.txt)")); //弹出文件选择框,保存文件 //检查是否为空 if(fileName != NULL) { QFile file(fileName); //创建一个 QFile 对象,用于操作文件 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return; //打开文件失败,则直接返回 } QTextStream out(&file); //创建一个QTextStream 对象,用于将数据写入文件 out <textEditRev->toPlainText(); //获取文本内容,输出到流out file.close(); //关闭文件 } } //更新串口调试助手时间 void Widget::time_reflash() { getSysTime(); //获取时间 ui->labelCurrentTime->setText(MyTime); //显示系统时间 } //获取系统时间 void Widget::getSysTime() { QDateTime currentTime = QDateTime::currentDateTime(); //创建一个currentTime对象,直接调用,返回当前系统时间 QDate date = currentTime.date(); //currentTime提取日期,返回一个日期对象date int year = date.year(); //获取年份,存储在year变量中 int month = date.month(); //获取月份,存储在month变量中 int day = date.day(); //获取日,存储在day变量中 QTime time = currentTime.time(); //创建一个time对象,返回时间 int hour = time.hour(); //获取时,存储在hour变量中 int minute = time.minute(); //获取时,存储在minute变量中 int second = time.second(); //获取时,存储在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')); //arg替换为实际的值,2为字段宽度,10为10进制 } //Hex显示 void Widget::on_checkBoxHexDisplay_clicked(bool checked) { if(checked) //如果打勾 { //1.读取textEdit内容 QString tmp = ui->textEditRev->toPlainText(); //2.转换成hex(因为QByteArray有toHex(),所以转换成QByteArray) QByteArray qtmp = tmp.toUtf8(); //因为QSrting没有把小写字母a转化成61的能力,QByteArray有,所以用QByteArray qtmp = qtmp.toHex(); //3.显示 QString lastShow; //定义一个lastShow,存储最终显示内容 tmp = QString::fromUtf8(qtmp); //把QByteArray转换成QString格式 for(int i = 0; itextEditRev->setText(lastShow.toUpper()); //转换成大写 } //非十六进制显示 else { //1.读取textEdit内容,hex QString tmpHexString = ui->textEditRev->toPlainText(); //2.将 QString 转换为 QByteArray QByteArray tmpHexQBytearray = tmpHexString.toUtf8(); //3.将十六进制字符串转换为字节数组 QByteArray tmpQByteString = QByteArray::fromHex(tmpHexQBytearray); //将61转换成a //4.显示 ui->textEditRev->setText(QString::fromUtf8(tmpQByteString)); } } ``` #### 串口调试助手隐藏面板和隐藏历史 Widget.h ``` #ifndef WIDGET_H #define WIDGET_H #include #include QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private slots: void on_btncloseorOpen_clicked(bool checked); //打开或关闭串口 void on_btnSendContex_clicked(); //发送数据 void on_SerialData_readyToRead(); //准备去读数据 void on_checkBoxSendInTime_clicked(bool checked); //定时发送 void on_btnrevClear_clicked(); //接收清楚 void on_btnrevSave_clicked(); //保存接收 void time_reflash(); //更新系统时间 void on_checkBoxHexDisplay_clicked(bool checked); //Hex显示 void on_btnhideTable_clicked(bool checked); //隐藏面板 void on_btnHideHistory_clicked(bool checked); //隐藏历史 private: QSerialPort *serialPort; //声明一个对象,串口 int writeCntTotal; //统计发送了多少字节 int readCntTotal; //统计发送了多少字节 QString SendBack; //返回上一次输入的数据 QString MyTime; //系统时间 bool serialStatus; //确认状态 QTimer *timer; //定时发送 void getSysTime(); //获取系统时间 Ui::Widget *ui; }; #endif // WIDGET_H ``` Widget.cpp ``` #include "widget.h" #include "ui_widget.h" #include #include #include #include #include #include Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); this->setLayout(ui->gridLayoutGlobal); //让界面随着窗口变幻大小 ui->btnSendContex->setEnabled(false); //刚打开串口,发送按钮是失效的 ui->checkBoxSendInTime->setEnabled(false); //刚打开串口界面,定时发送选择框是失效的 ui->checkBoxrevTime->setEnabled(false); //刚打开串口界面,接收时间选择框是失效的 serialPort = new QSerialPort(this); //创建一个QSerialPort对象,将指针赋值给serialPort变量 QTimer *getSysTimeTimer = new QTimer(this); //创建一个QTimer对象,将指针赋值给getSysTimeTimer connect(getSysTimeTimer,SIGNAL(timeout()),this,SLOT(time_reflash())); getSysTimeTimer->start(100); //启动定时器,每隔100毫秒触发一次timeout信号 timer = new QTimer(this); //创建一个时间对象 //控制参数初始化 writeCntTotal = 0; //写入字节数 readCntTotal = 0; //读取字节数 serialStatus = false; //失效状态 //控件初始化 ui->btnSendContex->setEnabled(false); //发送按钮失效 ui->checkBoxSendInTime->setEnabled(false); //定时发送按钮失效 ui->checkSendNewLine->setEnabled(false); //发送新行失效 ui->checkBHexSend->setEnabled(false); //HEX发送失效 connect(timer,&QTimer::timeout,this,[=](){ on_btnSendContex_clicked(); }); //连接信号与槽,到点就发送文本 connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_SerialData_readyToRead); //连接函数,当接收数据可读时 ui->comboBox_boautrate->setCurrentIndex(6); //将波特率索引值设置为6,方便选择 ui->comboBox_databit->setCurrentIndex(3); //将数据位索引值设置为3,方便选择 QList serialList= QSerialPortInfo::availablePorts(); //获取系统中可用的串口 for(QSerialPortInfo serialInfo : serialList) //遍历所有可用串口 { qDebug() << serialInfo.portName(); ui->comboBox_serialnum->addItem(serialInfo.portName()); //将serialInfo对象所代表的串口添加到UI中 } ui->labelSendStatus->setText(ui->comboBox_serialnum->itemText(0)+" " + "NoOpen"); //状态文本初始化 } Widget::~Widget() { delete ui; } void Widget::on_btncloseorOpen_clicked(bool checked) { if(checked) { //1.选择端口号 serialPort->setPortName(ui->comboBox_serialnum->currentText()); //获取串口,把串口显示到文本上 //2.配置波特率 serialPort->setBaudRate(ui->comboBox_boautrate->currentText().toInt()); //显示波特率,转整型 //3.配置数据位 serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_databit->currentText().toInt())); //显示波特率,转整型 //4.配置校验位 switch (ui->comboBox_jiaoyan->currentText().toInt()) //用户选择校验位,并转为整型 { 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; } //5.配置停止位 serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_stopbit->currentText().toInt())); //显示停止位,转整型 //6.流控 if(ui->comboBox_fluidCon->currentText() == "None") //用户选择了None { serialPort->setFlowControl(QSerialPort::NoFlowControl); //执行,无流控 } //7.打开串口 if(serialPort->open(QIODevice::ReadWrite)) { qDebug() << "serial open success"; ui->comboBox_databit->setEnabled(false); //成功打开串口,这些按钮就失效 ui->comboBox_fluidCon->setEnabled(false); ui->comboBox_jiaoyan->setEnabled(false); ui->comboBox_stopbit->setEnabled(false); ui->comboBox_boautrate->setEnabled(false); ui->comboBox_serialnum->setEnabled(false); ui->btncloseorOpen->setText("关闭串口"); ui->btnSendContex->setEnabled(true); ui->checkBoxSendInTime->setEnabled(true); //成功打开串口,定时发送按钮生效 ui->checkSendNewLine->setEnabled(true); //发送新行生效 ui->checkBHexSend->setEnabled(true); //HEX发送生效 ui->labelSendStatus->setText(ui->comboBox_serialnum->currentText() + " " + "isOpen"); } else { qDebug() << "error"; QMessageBox msgBox; //弹窗 msgBox.setWindowTitle("打开串口错误"); msgBox.setText("打开失败,串口可能被占用或已拔出"); msgBox.exec(); } } else { serialPort->close(); ui->btncloseorOpen->setText("打开串口"); ui->comboBox_databit->setEnabled(true); //没有打开串口,这些按钮都是生效的 ui->comboBox_fluidCon->setEnabled(true); ui->comboBox_jiaoyan->setEnabled(true); ui->comboBox_stopbit->setEnabled(true); ui->comboBox_boautrate->setEnabled(true); ui->comboBox_serialnum->setEnabled(true); //serialStatus = false; ui->btnSendContex->setEnabled(false); //没有打开串口,发送按钮失效 ui->checkBoxSendInTime->setEnabled(false); //打开串口失败,定时发送按钮失效 ui->checkBoxSendInTime->setCheckState(Qt::Unchecked); //设置复选框为未选中状态 //关闭定时器 timer->stop(); ui->lineEditTimeeach->setEnabled(true); ui->lineEditSendContex->setEnabled(true); ui->checkSendNewLine->setEnabled(false); //发送新行失效 ui->checkBHexSend->setEnabled(false); //HEX发送失效 ui->labelSendStatus->setText(ui->comboBox_serialnum->currentText() + " " + "isClose"); } } //发送数据 void Widget::on_btnSendContex_clicked() { int writeCnt = 0; const char* sendData = ui->lineEditSendContex->text().toLocal8Bit().constData(); //把发送文本转换为C字符串指针 if(ui->checkBHexSend->isChecked()) //判断按键是否被按下 { QString tmp = ui->lineEditSendContex->text().toLocal8Bit().constData(); //判断是否是偶数位,16进制是两位 QByteArray tmpArray = tmp.toLocal8Bit(); if(tmpArray.size() % 2 != 0) { ui->labelSendStatus->setText("Error Input"); } //判断是否符合16进制的表达 for(char c : tmpArray) //定义一个c,遍历tmpArray数组 { if(!std::isxdigit(c)) //判断每一位是不是十六进制 { ui->labelSendStatus->setText("Error Input"); return; } } if(ui->checkSendNewLine->isChecked()) { tmpArray.append("\r\n"); //转换成16进制发送,用户输入1,变成1,不会变成字符1,ASCII码 QByteArray arraySend = QByteArray::fromHex(tmpArray); //发送16进制 writeCnt = serialPort->write(arraySend); } } else { //如果不是16进制发送 if(ui->checkSendNewLine->isChecked()) { QByteArray arraySendData(sendData,strlen(sendData)); qDebug() << "bbbb"; arraySendData.append("\r\n"); writeCnt = serialPort->write(arraySendData); //返回实际写入的字节数 } else { writeCnt = serialPort->write(sendData); //返回实际写入的字节数 } } //发送失败清空 if(writeCnt == -1) { ui->labelSendStatus->setText("Send Error!"); //返回字节数失败,表示发送错误 } else { writeCntTotal += writeCnt; //写入成功,将字节数累加到writeCntTotal变量上 qDebug() << "SendOK" << sendData; //输出SendOK和sendData里面的内容 ui->labelSendStatus->setText("Send OK!"); //把发送状态改为Send OK ui->labelSendcnt->setNum(writeCntTotal); if(strcmp(sendData,SendBack.toStdString().c_str()) != 0) //比较sendData和上一次输出的数据是否相同 { ui->textEditRecord->append(sendData); //不同则在textEditRecord里追加数据 SendBack = QString::fromUtf8(sendData); //将数据转成QString类型,以便下次使用 } } } //读取发送的数据 void Widget::on_SerialData_readyToRead() { QString revMessage = serialPort->readAll(); //读取数据存于revMessage // qDebug() << "revCnt" << revMessage.size() << "context:" << revMessage; if(revMessage != NULL) //检查指针 revMessage 是否为非空指针,读取数据不为空 { if(ui->checkBLine->isChecked()) { revMessage.append("\r\n"); } //16进制显示 if(ui->checkBoxHexDisplay->isChecked()) //判断Hex显示是否被勾选 { QByteArray tmpHexString = revMessage.toUtf8().toHex().toUpper(); //原来控件上的内容,hex QString tmpStringHex = ui->textEditRev->toPlainText(); //因为勾选了,读出来就是Hex tmpHexString = tmpStringHex.toUtf8() + tmpHexString; //把读出的就的hex和新收到的数据转成hex进行拼接 ui->textEditRev->setText(QString::fromUtf8(tmpHexString)); //重新显示在控件上 } //非十六进制显示 else { if(ui->checkSendNewLine->isChecked()) { revMessage.append("\r\n"); } if(ui->checkBoxrevTime->isChecked()) { getSysTime(); QString message = ui->lineEditSendContex->text() + " " + "【"+MyTime+"】"; ui->textEditRev->insertPlainText(message); } else { ui->textEditRev->insertPlainText(revMessage); //将收到的内容追加到textEditRev文本框中 } } } readCntTotal += revMessage.size(); //接收的总字节数 ui->labelRevcnt->setNum(readCntTotal); //计算接收到的字节数 } //自动发送 void Widget::on_checkBoxSendInTime_clicked(bool checked) { // qDebug() <<"checkBsendIntime" << checked; if(checked) //检测复选框是否被选中 { ui->lineEditTimeeach->setEnabled(false); //定时发送开始,定时文本无效 ui->lineEditTimeeach->setEnabled(false); //定时发送开始,发送文本无效 timer->start(1000); //启动定时器 timer->start(ui->lineEditTimeeach->text().toInt()); //允许用户修改时间间隔 //on_btnSendContex_clicked(); } else { timer->stop(); //停止定时器 ui->lineEditTimeeach->setEnabled(true); //定时器停止后,定时文本变有效 ui->lineEditSendContex->setEnabled(true); //定时器停止后,发送文本变有效 } } //清空接收 void Widget::on_btnrevClear_clicked() { ui->textEditRev->setText(""); //清空接收内容 } //保存接收内容 void Widget::on_btnrevSave_clicked() { QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "L:/QTproject/QT/serialData.txt", tr("Text (*.txt)")); //弹出文件选择框,保存文件 if(fileName != NULL) { QFile file(fileName); //创建一个 QFile 对象,用于操作文件 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return; //打开文件失败,则直接返回 } QTextStream out(&file); //创建一个QTextStream 对象,用于将数据写入文件 out <textEditRev->toPlainText(); //获取文本内容,输出到流out file.close(); //关闭文件 } } //更新串口调试助手时间 void Widget::time_reflash() { getSysTime(); ui->labelCurrentTime->setText(MyTime); } //获取系统时间 void Widget::getSysTime() { QDateTime currentTime = QDateTime::currentDateTime(); //创建一个currentTime对象,返回当前系统时间 QDate date = currentTime.date(); //返回一个日期对象date int year = date.year(); //获取年份,存储在year变量中 int month = date.month(); //获取月份,存储在month变量中 int day = date.day(); //获取日,存储在day变量中 QTime time = currentTime.time(); //创建一个time对象,返回时间 int hour = time.hour(); //获取时,存储在hour变量中 int minute = time.minute(); //获取时,存储在minute变量中 int second = time.second(); //获取时,存储在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')); } //Hex显示 void Widget::on_checkBoxHexDisplay_clicked(bool checked) { if(checked) //如果打勾 { //1.读取textEdit内容 QString tmp = ui->textEditRev->toPlainText(); //2.转换成hex(因为QByteArray有toHex(),所以转换成QByteArray) QByteArray qtmp = tmp.toUtf8(); //因为QSrting没有把小写字母a转化成61的能力,QByteArray有,所以用QByteArray qtmp = qtmp.toHex(); //3.显示 QString lastShow; tmp = QString::fromUtf8(qtmp); //把QByteArray转换成QString格式 for(int i = 0; itextEditRev->setText(lastShow.toUpper()); //转换成大写 } else { //1.读取textEdit内容,hex QString tmpHexString = ui->textEditRev->toPlainText(); //2.将 QString 转换为 QByteArray QByteArray tmpHexQBytearray = tmpHexString.toUtf8(); //3.将十六进制字符串转换为字节数组 QByteArray tmpQByteString = QByteArray::fromHex(tmpHexQBytearray); //将61转换成a //4.显示 ui->textEditRev->setText(QString::fromUtf8(tmpQByteString)); } } void Widget::on_btnhideTable_clicked(bool checked) { //如果隐藏面板被勾选 if(checked) { ui->btnhideTable->setText("拓展面板"); //按钮改为拓展面板 ui->groupBoxTexts->hide(); //隐藏 } else { ui->btnhideTable->setText("隐藏面板"); //面板已打开,按钮改为隐藏面板 ui->groupBoxTexts->show(); //展示 } } void Widget::on_btnHideHistory_clicked(bool checked) { if(checked) { ui->btnHideHistory->setText("显示历史"); ui->groupBoxRecord->hide(); //隐藏 } else { ui->btnHideHistory->setText("隐藏历史"); //历史已打开,按钮改为隐藏历史 ui->groupBoxRecord->show(); //展示 } } ``` #### 串口调试助手刷新串口 Widget.h ``` #ifndef WIDGET_H #define WIDGET_H #include #include #include "mycombobox.h" QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private slots: void on_btncloseorOpen_clicked(bool checked); //打开或关闭串口 void on_btnSendContex_clicked(); //发送数据 void on_SerialData_readyToRead(); //准备去读数据 void on_checkBoxSendInTime_clicked(bool checked); //定时发送 void on_btnrevClear_clicked(); //接收清楚 void on_btnrevSave_clicked(); //保存接收 void time_reflash(); //更新系统时间 void on_checkBoxHexDisplay_clicked(bool checked); //Hex显示 void on_btnhideTable_clicked(bool checked); //隐藏面板 void on_btnHideHistory_clicked(bool checked); //隐藏历史 void refreshSerialName(); //刷新串口名字 private: QSerialPort *serialPort; //声明一个对象,串口 int writeCntTotal; //统计发送了多少字节 int readCntTotal; //统计发送了多少字节 QString SendBack; //返回上一次输入的数据 QString MyTime; //系统时间 bool serialStatus; //确认状态 QTimer *timer; //定时发送 void getSysTime(); //获取系统时间 Ui::Widget *ui; }; #endif // WIDGET_H ``` mycombobox.h ``` #ifndef MYCOMBOBOX_H #define MYCOMBOBOX_H #include #include class MyComboBox : public QComboBox { Q_OBJECT //宏定义,用于启用 Qt 的元对象系统,用到信号与槽,需要添加 public: MyComboBox(QWidget*parent); //构造函数声明 protected: void mousePressEvent(QMouseEvent *e) override; //重写鼠标按下事件处理函数 signals: void refresh(); //刷新信号 }; #endif // MYCOMBOBOX_H ``` Widget.cpp ``` #include "widget.h" #include "ui_widget.h" #include #include #include #include #include #include Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); this->setLayout(ui->gridLayoutGlobal); //让界面随着窗口变幻大小 ui->btnSendContex->setEnabled(false); //刚打开串口,发送按钮是失效的 ui->checkBoxSendInTime->setEnabled(false); //刚打开串口界面,定时发送选择框是失效的 ui->checkBoxrevTime->setEnabled(false); //刚打开串口界面,接收时间选择框是失效的 serialPort = new QSerialPort(this); //创建一个QSerialPort对象,将指针赋值给serialPort变量 QTimer *getSysTimeTimer = new QTimer(this); //创建一个QTimer对象,将指针赋值给getSysTimeTimer connect(getSysTimeTimer,SIGNAL(timeout()),this,SLOT(time_reflash())); getSysTimeTimer->start(100); //启动定时器,每隔100毫秒触发一次timeout信号 timer = new QTimer(this); //创建一个时间对象 //控制参数初始化 writeCntTotal = 0; //写入字节数 readCntTotal = 0; //读取字节数 serialStatus = false; //失效状态 //控件初始化 ui->btnSendContex->setEnabled(false); //发送按钮失效 ui->checkBoxSendInTime->setEnabled(false); //定时发送按钮失效 ui->checkSendNewLine->setEnabled(false); //发送新行失效 ui->checkBHexSend->setEnabled(false); //HEX发送失效 connect(timer,&QTimer::timeout,this,[=](){ on_btnSendContex_clicked(); }); //连接信号与槽,到点就发送文本 connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_SerialData_readyToRead); //连接函数,当接收数据可读时 connect(ui->comboBox_serialnum,&MyComboBox::refresh,this,&Widget::refreshSerialName); ui->comboBox_boautrate->setCurrentIndex(6); //将波特率索引值设置为6,方便选择 ui->comboBox_databit->setCurrentIndex(3); //将数据位索引值设置为3,方便选择 refreshSerialName(); ui->labelSendStatus->setText(ui->comboBox_serialnum->itemText(0)+" " + "NoOpen"); //状态文本初始化 } Widget::~Widget() { delete ui; } void Widget::on_btncloseorOpen_clicked(bool checked) { if(checked) { //1.选择端口号 serialPort->setPortName(ui->comboBox_serialnum->currentText()); //获取串口,把串口显示到文本上 //2.配置波特率 serialPort->setBaudRate(ui->comboBox_boautrate->currentText().toInt()); //显示波特率,转整型 //3.配置数据位 serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_databit->currentText().toInt())); //显示波特率,转整型 //4.配置校验位 switch (ui->comboBox_jiaoyan->currentText().toInt()) //用户选择校验位,并转为整型 { 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; } //5.配置停止位 serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_stopbit->currentText().toInt())); //显示停止位,转整型 //6.流控 if(ui->comboBox_fluidCon->currentText() == "None") //用户选择了None { serialPort->setFlowControl(QSerialPort::NoFlowControl); //执行,无流控 } //7.打开串口 if(serialPort->open(QIODevice::ReadWrite)) { qDebug() << "serial open success"; ui->comboBox_databit->setEnabled(false); //成功打开串口,这些按钮就失效 ui->comboBox_fluidCon->setEnabled(false); ui->comboBox_jiaoyan->setEnabled(false); ui->comboBox_stopbit->setEnabled(false); ui->comboBox_boautrate->setEnabled(false); ui->comboBox_serialnum->setEnabled(false); ui->btncloseorOpen->setText("关闭串口"); ui->btnSendContex->setEnabled(true); ui->checkBoxSendInTime->setEnabled(true); //成功打开串口,定时发送按钮生效 ui->checkSendNewLine->setEnabled(true); //发送新行生效 ui->checkBHexSend->setEnabled(true); //HEX发送生效 ui->labelSendStatus->setText(ui->comboBox_serialnum->currentText() + " " + "isOpen"); } else { qDebug() << "error"; QMessageBox msgBox; //弹窗 msgBox.setWindowTitle("打开串口错误"); msgBox.setText("打开失败,串口可能被占用或已拔出"); msgBox.exec(); } } else { serialPort->close(); ui->btncloseorOpen->setText("打开串口"); ui->comboBox_databit->setEnabled(true); //没有打开串口,这些按钮都是生效的 ui->comboBox_fluidCon->setEnabled(true); ui->comboBox_jiaoyan->setEnabled(true); ui->comboBox_stopbit->setEnabled(true); ui->comboBox_boautrate->setEnabled(true); ui->comboBox_serialnum->setEnabled(true); //serialStatus = false; ui->btnSendContex->setEnabled(false); //没有打开串口,发送按钮失效 ui->checkBoxSendInTime->setEnabled(false); //打开串口失败,定时发送按钮失效 ui->checkBoxSendInTime->setCheckState(Qt::Unchecked); //设置复选框为未选中状态 //关闭定时器 timer->stop(); ui->lineEditTimeeach->setEnabled(true); ui->lineEditSendContex->setEnabled(true); ui->checkSendNewLine->setEnabled(false); //发送新行失效 ui->checkBHexSend->setEnabled(false); //HEX发送失效 ui->labelSendStatus->setText(ui->comboBox_serialnum->currentText() + " " + "isClose"); } } //发送数据 void Widget::on_btnSendContex_clicked() { int writeCnt = 0; const char* sendData = ui->lineEditSendContex->text().toLocal8Bit().constData(); //把发送文本转换为C字符串指针 if(ui->checkBHexSend->isChecked()) //判断按键是否被按下 { QString tmp = ui->lineEditSendContex->text().toLocal8Bit().constData(); //判断是否是偶数位,16进制是两位 QByteArray tmpArray = tmp.toLocal8Bit(); if(tmpArray.size() % 2 != 0) { ui->labelSendStatus->setText("Error Input"); } //判断是否符合16进制的表达 for(char c : tmpArray) //定义一个c,遍历tmpArray数组 { if(!std::isxdigit(c)) //判断每一位是不是十六进制 { ui->labelSendStatus->setText("Error Input"); return; } } //转换成16进制发送,用户输入1,变成1,不会变成字符1,ASCII码 QByteArray arraySend = QByteArray::fromHex(tmpArray); //发送16进制 writeCnt = serialPort->write(arraySend); } else { //如果不是16进制发送 if(ui->checkSendNewLine->isChecked()) { QByteArray arraySendData(sendData,strlen(sendData)); qDebug() << "bbbb"; arraySendData.append("\r\n"); writeCnt = serialPort->write(arraySendData); //返回实际写入的字节数 } else { writeCnt = serialPort->write(sendData); //返回实际写入的字节数 } } //发送失败清空 if(writeCnt == -1) { ui->labelSendStatus->setText("Send Error!"); //返回字节数失败,表示发送错误 } else { writeCntTotal += writeCnt; //写入成功,将字节数累加到writeCntTotal变量上 qDebug() << "SendOK" << sendData; //输出SendOK和sendData里面的内容 ui->labelSendStatus->setText("Send OK!"); //把发送状态改为Send OK ui->labelSendcnt->setNum(writeCntTotal); if(strcmp(sendData,SendBack.toStdString().c_str()) != 0) //比较sendData和上一次输出的数据是否相同 { ui->textEditRecord->append(sendData); //不同则在textEditRecord里追加数据 SendBack = QString::fromUtf8(sendData); //将数据转成QString类型,以便下次使用 } } } //读取发送的数据 void Widget::on_SerialData_readyToRead() { QString revMessage = serialPort->readAll(); //读取数据存于revMessage // qDebug() << "revCnt" << revMessage.size() << "context:" << revMessage; if(revMessage != NULL) //检查指针 revMessage 是否为非空指针,读取数据不为空 { if(ui->checkBLine->isChecked()) { revMessage.append("\r\n"); } //16进制显示 if(ui->checkBoxHexDisplay->isChecked()) //判断Hex显示是否被勾选 { QByteArray tmpHexString = revMessage.toUtf8().toHex().toUpper(); //原来控件上的内容,hex QString tmpStringHex = ui->textEditRev->toPlainText(); //因为勾选了,读出来就是Hex tmpHexString = tmpStringHex.toUtf8() + tmpHexString; //把读出的就的hex和新收到的数据转成hex进行拼接 ui->textEditRev->setText(QString::fromUtf8(tmpHexString)); //重新显示在控件上 } //非十六进制显示 else { if(ui->checkSendNewLine->isChecked()) { revMessage.append("\r\n"); } if(ui->checkBoxrevTime->isChecked()) { getSysTime(); QString message = ui->lineEditSendContex->text() + " " + "【"+MyTime+"】"; ui->textEditRev->insertPlainText(message); } else { ui->textEditRev->insertPlainText(revMessage); //将收到的内容追加到textEditRev文本框中 } } } readCntTotal += revMessage.size(); //接收的总字节数 ui->labelRevcnt->setNum(readCntTotal); //计算接收到的字节数 } //自动发送 void Widget::on_checkBoxSendInTime_clicked(bool checked) { // qDebug() <<"checkBsendIntime" << checked; if(checked) //检测复选框是否被选中 { ui->lineEditTimeeach->setEnabled(false); //定时发送开始,定时文本无效 ui->lineEditTimeeach->setEnabled(false); //定时发送开始,发送文本无效 timer->start(1000); //启动定时器 timer->start(ui->lineEditTimeeach->text().toInt()); //允许用户修改时间间隔 //on_btnSendContex_clicked(); } else { timer->stop(); //停止定时器 ui->lineEditTimeeach->setEnabled(true); //定时器停止后,定时文本变有效 ui->lineEditSendContex->setEnabled(true); //定时器停止后,发送文本变有效 } } //清空接收 void Widget::on_btnrevClear_clicked() { ui->textEditRev->setText(""); //清空接收内容 } //保存接收内容 void Widget::on_btnrevSave_clicked() { QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "L:/QTproject/QT/serialData.txt", tr("Text (*.txt)")); //弹出文件选择框,保存文件 if(fileName != NULL) { QFile file(fileName); //创建一个 QFile 对象,用于操作文件 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return; //打开文件失败,则直接返回 } QTextStream out(&file); //创建一个QTextStream 对象,用于将数据写入文件 out <textEditRev->toPlainText(); //获取文本内容,输出到流out file.close(); //关闭文件 } } //更新串口调试助手时间 void Widget::time_reflash() { getSysTime(); ui->labelCurrentTime->setText(MyTime); } //获取系统时间 void Widget::getSysTime() { QDateTime currentTime = QDateTime::currentDateTime(); //创建一个currentTime对象,返回当前系统时间 QDate date = currentTime.date(); //返回一个日期对象date int year = date.year(); //获取年份,存储在year变量中 int month = date.month(); //获取月份,存储在month变量中 int day = date.day(); //获取日,存储在day变量中 QTime time = currentTime.time(); //创建一个time对象,返回时间 int hour = time.hour(); //获取时,存储在hour变量中 int minute = time.minute(); //获取时,存储在minute变量中 int second = time.second(); //获取时,存储在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')); } //Hex显示 void Widget::on_checkBoxHexDisplay_clicked(bool checked) { if(checked) //如果打勾 { //1.读取textEdit内容 QString tmp = ui->textEditRev->toPlainText(); //2.转换成hex(因为QByteArray有toHex(),所以转换成QByteArray) QByteArray qtmp = tmp.toUtf8(); //因为QSrting没有把小写字母a转化成61的能力,QByteArray有,所以用QByteArray qtmp = qtmp.toHex(); //3.显示 QString lastShow; tmp = QString::fromUtf8(qtmp); //把QByteArray转换成QString格式 for(int i = 0; itextEditRev->setText(lastShow.toUpper()); //转换成大写 } else { //1.读取textEdit内容,hex QString tmpHexString = ui->textEditRev->toPlainText(); //2.将 QString 转换为 QByteArray QByteArray tmpHexQBytearray = tmpHexString.toUtf8(); //3.将十六进制字符串转换为字节数组 QByteArray tmpQByteString = QByteArray::fromHex(tmpHexQBytearray); //将61转换成a //4.显示 ui->textEditRev->setText(QString::fromUtf8(tmpQByteString)); } } void Widget::on_btnhideTable_clicked(bool checked) { if(checked) { ui->btnhideTable->setText("拓展面板"); ui->groupBoxTexts->hide(); //隐藏 } else { ui->btnhideTable->setText("隐藏面板"); ui->groupBoxTexts->show(); //展示 } } void Widget::on_btnHideHistory_clicked(bool checked) { if(checked) { ui->btnHideHistory->setText("显示历史"); ui->groupBoxRecord->hide(); //隐藏 } else { ui->btnHideHistory->setText("隐藏历史"); ui->groupBoxRecord->show(); //展示 } } //刷新串口号 void Widget::refreshSerialName() { ui->comboBox_serialnum->clear(); //清空comboBox QList serialList= QSerialPortInfo::availablePorts(); //获取系统中可用的串口 for(QSerialPortInfo serialInfo : serialList) //遍历所有可用串口 { qDebug() << serialInfo.portName(); ui->comboBox_serialnum->addItem(serialInfo.portName()); //将serialInfo对象所代表的串口添加到UI中 } ui->labelSendStatus->setText("Com Refresh"); } ``` mycombobox.cpp ``` #include "mycombobox.h" #include MyComboBox::MyComboBox(QWidget *parent):QComboBox(parent) { } void MyComboBox::mousePressEvent(QMouseEvent *e) { if(e->button() == Qt::LeftButton) //判断鼠标左键是否按下 { emit refresh(); //发送刷新信号 } QComboBox::mousePressEvent(e); //调用基类的mousePressEvent方法,确保默认行为仍然被执行 } ``` #### 串口调试助手固定序号发送 Widget.h ``` #ifndef WIDGET_H #define WIDGET_H #include #include #include "mycombobox.h" QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private slots: void on_btncloseorOpen_clicked(bool checked); //打开或关闭串口 void on_btnSendContex_clicked(); //发送数据 void on_SerialData_readyToRead(); //准备去读数据 void on_checkBoxSendInTime_clicked(bool checked); //定时发送 void on_btnrevClear_clicked(); //接收清楚 void on_btnrevSave_clicked(); //保存接收 void time_reflash(); //更新系统时间 void on_checkBoxHexDisplay_clicked(bool checked); //Hex显示 void on_btnhideTable_clicked(bool checked); //隐藏面板 void on_btnHideHistory_clicked(bool checked); //隐藏历史 void refreshSerialName(); //刷新串口名字 void on_command_button_clicked(); //序号被点击 private: QSerialPort *serialPort; //声明一个对象,串口 int writeCntTotal; //统计发送了多少字节 int readCntTotal; //统计发送了多少字节 QString SendBack; //返回上一次输入的数据 QString MyTime; //系统时间 bool serialStatus; //确认状态 QTimer *timer; //定时发送 void getSysTime(); //获取系统时间 Ui::Widget *ui; }; #endif // WIDGET_H ``` Widget.cpp ``` #include "widget.h" #include "ui_widget.h" #include #include #include #include #include #include Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); this->setLayout(ui->gridLayoutGlobal); //让界面随着窗口变幻大小 ui->btnSendContex->setEnabled(false); //刚打开串口,发送按钮是失效的 ui->checkBoxSendInTime->setEnabled(false); //刚打开串口界面,定时发送选择框是失效的 ui->checkBoxrevTime->setEnabled(false); //刚打开串口界面,接收时间选择框是失效的 serialPort = new QSerialPort(this); //创建一个QSerialPort对象,将指针赋值给serialPort变量 QTimer *getSysTimeTimer = new QTimer(this); //创建一个QTimer对象,将指针赋值给getSysTimeTimer connect(getSysTimeTimer,SIGNAL(timeout()),this,SLOT(time_reflash())); getSysTimeTimer->start(100); //启动定时器,每隔100毫秒触发一次timeout信号 timer = new QTimer(this); //创建一个时间对象 //控制参数初始化 writeCntTotal = 0; //写入字节数 readCntTotal = 0; //读取字节数 serialStatus = false; //失效状态 //控件初始化 ui->btnSendContex->setEnabled(false); //发送按钮失效 ui->checkBoxSendInTime->setEnabled(false); //定时发送按钮失效 ui->checkSendNewLine->setEnabled(false); //发送新行失效 ui->checkBHexSend->setEnabled(false); //HEX发送失效 connect(timer,&QTimer::timeout,this,[=](){ on_btnSendContex_clicked(); }); //连接信号与槽,到点就发送文本 connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_SerialData_readyToRead); //连接函数,当接收数据可读时 connect(ui->comboBox_serialnum,&MyComboBox::refresh,this,&Widget::refreshSerialName); ui->comboBox_boautrate->setCurrentIndex(6); //将波特率索引值设置为6,方便选择 ui->comboBox_databit->setCurrentIndex(3); //将数据位索引值设置为3,方便选择 refreshSerialName(); ui->labelSendStatus->setText(ui->comboBox_serialnum->itemText(0)+" " + "NoOpen"); //状态文本初始化 QListbuttons; for(int i = 1; i<=9; i++) { QString btnName = QString("pushButton_%1").arg(i); //从1到9 QPushButton* btn = findChild (btnName); if(btn) { btn->setProperty("buttonId",i); buttons.append(btn); connect(btn,SIGNAL(clicked()),this,SLOT(on_command_button_clicked())); } } } Widget::~Widget() { delete ui; } //打开或关闭串口 void Widget::on_btncloseorOpen_clicked(bool checked) { if(checked) { //1.选择端口号 serialPort->setPortName(ui->comboBox_serialnum->currentText()); //获取串口,把串口显示到文本上 //2.配置波特率 serialPort->setBaudRate(ui->comboBox_boautrate->currentText().toInt()); //显示波特率,转整型 //3.配置数据位 serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_databit->currentText().toInt())); //显示波特率,转整型 //4.配置校验位 switch (ui->comboBox_jiaoyan->currentText().toInt()) //用户选择校验位,并转为整型 { 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; } //5.配置停止位 serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_stopbit->currentText().toInt())); //显示停止位,转整型 //6.流控 if(ui->comboBox_fluidCon->currentText() == "None") //用户选择了None { serialPort->setFlowControl(QSerialPort::NoFlowControl); //执行,无流控 } //7.打开串口 if(serialPort->open(QIODevice::ReadWrite)) { qDebug() << "serial open success"; ui->comboBox_databit->setEnabled(false); //成功打开串口,这些按钮就失效 ui->comboBox_fluidCon->setEnabled(false); ui->comboBox_jiaoyan->setEnabled(false); ui->comboBox_stopbit->setEnabled(false); ui->comboBox_boautrate->setEnabled(false); ui->comboBox_serialnum->setEnabled(false); ui->btncloseorOpen->setText("关闭串口"); ui->btnSendContex->setEnabled(true); ui->checkBoxSendInTime->setEnabled(true); //成功打开串口,定时发送按钮生效 ui->checkSendNewLine->setEnabled(true); //发送新行生效 ui->checkBHexSend->setEnabled(true); //HEX发送生效 ui->labelSendStatus->setText(ui->comboBox_serialnum->currentText() + " " + "isOpen"); } else { qDebug() << "error"; QMessageBox msgBox; //弹窗 msgBox.setWindowTitle("打开串口错误"); msgBox.setText("打开失败,串口可能被占用或已拔出"); msgBox.exec(); } } else { serialPort->close(); ui->btncloseorOpen->setText("打开串口"); ui->comboBox_databit->setEnabled(true); //没有打开串口,这些按钮都是生效的 ui->comboBox_fluidCon->setEnabled(true); ui->comboBox_jiaoyan->setEnabled(true); ui->comboBox_stopbit->setEnabled(true); ui->comboBox_boautrate->setEnabled(true); ui->comboBox_serialnum->setEnabled(true); //serialStatus = false; ui->btnSendContex->setEnabled(false); //没有打开串口,发送按钮失效 ui->checkBoxSendInTime->setEnabled(false); //打开串口失败,定时发送按钮失效 ui->checkBoxSendInTime->setCheckState(Qt::Unchecked); //设置复选框为未选中状态 //关闭定时器 timer->stop(); ui->lineEditTimeeach->setEnabled(true); ui->lineEditSendContex->setEnabled(true); ui->checkSendNewLine->setEnabled(false); //发送新行失效 ui->checkBHexSend->setEnabled(false); //HEX发送失效 ui->labelSendStatus->setText(ui->comboBox_serialnum->currentText() + " " + "isClose"); } } //发送数据 void Widget::on_btnSendContex_clicked() { int writeCnt = 0; const char* sendData = ui->lineEditSendContex->text().toLocal8Bit().constData(); //把发送文本转换为C字符串指针 if(ui->checkBHexSend->isChecked()) //判断按键是否被按下 { QString tmp = ui->lineEditSendContex->text().toLocal8Bit().constData(); //判断是否是偶数位,16进制是两位 QByteArray tmpArray = tmp.toLocal8Bit(); if(tmpArray.size() % 2 != 0) { ui->labelSendStatus->setText("Error Input"); } //判断是否符合16进制的表达 for(char c : tmpArray) //定义一个c,遍历tmpArray数组 { if(!std::isxdigit(c)) //判断每一位是不是十六进制 { ui->labelSendStatus->setText("Error Input"); return; } } //转换成16进制发送,用户输入1,变成1,不会变成字符1,ASCII码 QByteArray arraySend = QByteArray::fromHex(tmpArray); //发送16进制 writeCnt = serialPort->write(arraySend); } else { //如果不是16进制发送 if(ui->checkSendNewLine->isChecked()) { QByteArray arraySendData(sendData,strlen(sendData)); arraySendData.append("\r\n"); writeCnt = serialPort->write(arraySendData); //返回实际写入的字节数 } else { writeCnt = serialPort->write(sendData); //返回实际写入的字节数 } } //发送失败清空 if(writeCnt == -1) { ui->labelSendStatus->setText("Send Error!"); //返回字节数失败,表示发送错误 } else { writeCntTotal += writeCnt; //写入成功,将字节数累加到writeCntTotal变量上 qDebug() << "SendOK" << sendData; //输出SendOK和sendData里面的内容 ui->labelSendStatus->setText("Send OK!"); //把发送状态改为Send OK ui->labelSendcnt->setNum(writeCntTotal); if(strcmp(sendData,SendBack.toStdString().c_str()) != 0) //比较sendData和上一次输出的数据是否相同 { ui->textEditRecord->append(sendData); //不同则在textEditRecord里追加数据 SendBack = QString::fromUtf8(sendData); //将数据转成QString类型,以便下次使用 } } } //读取发送的数据 void Widget::on_SerialData_readyToRead() { QString revMessage = serialPort->readAll(); //读取数据存于revMessage // qDebug() << "revCnt" << revMessage.size() << "context:" << revMessage; if(revMessage != NULL) //检查指针 revMessage 是否为非空指针,读取数据不为空 { if(ui->checkBLine->isChecked()) { revMessage.append("\r\n"); } //16进制显示 if(ui->checkBoxHexDisplay->isChecked()) //判断Hex显示是否被勾选 { QByteArray tmpHexString = revMessage.toUtf8().toHex().toUpper(); //原来控件上的内容,hex QString tmpStringHex = ui->textEditRev->toPlainText(); //因为勾选了,读出来就是Hex tmpHexString = tmpStringHex.toUtf8() + tmpHexString; //把读出的就的hex和新收到的数据转成hex进行拼接 ui->textEditRev->setText(QString::fromUtf8(tmpHexString)); //重新显示在控件上 } //非十六进制显示 else { if(ui->checkBoxrevTime->isChecked()) { getSysTime(); QString message = ui->lineEditSendContex->text() + " " + "【"+MyTime+"】"; ui->textEditRev->insertPlainText(message); } else { ui->textEditRev->insertPlainText(revMessage); //将收到的内容追加到textEditRev文本框中 } } } readCntTotal += revMessage.size(); //接收的总字节数 ui->labelRevcnt->setNum(readCntTotal); //计算接收到的字节数 } //自动发送 void Widget::on_checkBoxSendInTime_clicked(bool checked) { // qDebug() <<"checkBsendIntime" << checked; if(checked) //检测复选框是否被选中 { ui->lineEditTimeeach->setEnabled(false); //定时发送开始,定时文本无效 ui->lineEditTimeeach->setEnabled(false); //定时发送开始,发送文本无效 timer->start(1000); //启动定时器 timer->start(ui->lineEditTimeeach->text().toInt()); //允许用户修改时间间隔 //on_btnSendContex_clicked(); } else { timer->stop(); //停止定时器 ui->lineEditTimeeach->setEnabled(true); //定时器停止后,定时文本变有效 ui->lineEditSendContex->setEnabled(true); //定时器停止后,发送文本变有效 } } //清空接收 void Widget::on_btnrevClear_clicked() { ui->textEditRev->setText(""); //清空接收内容 } //保存接收内容 void Widget::on_btnrevSave_clicked() { QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "L:/QTproject/QT/serialData.txt", tr("Text (*.txt)")); //弹出文件选择框,保存文件 if(fileName != NULL) { QFile file(fileName); //创建一个 QFile 对象,用于操作文件 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return; //打开文件失败,则直接返回 } QTextStream out(&file); //创建一个QTextStream 对象,用于将数据写入文件 out <textEditRev->toPlainText(); //获取文本内容,输出到流out file.close(); //关闭文件 } } //更新串口调试助手时间 void Widget::time_reflash() { getSysTime(); ui->labelCurrentTime->setText(MyTime); } //获取系统时间 void Widget::getSysTime() { QDateTime currentTime = QDateTime::currentDateTime(); //创建一个currentTime对象,返回当前系统时间 QDate date = currentTime.date(); //返回一个日期对象date int year = date.year(); //获取年份,存储在year变量中 int month = date.month(); //获取月份,存储在month变量中 int day = date.day(); //获取日,存储在day变量中 QTime time = currentTime.time(); //创建一个time对象,返回时间 int hour = time.hour(); //获取时,存储在hour变量中 int minute = time.minute(); //获取时,存储在minute变量中 int second = time.second(); //获取时,存储在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')); } //Hex显示 void Widget::on_checkBoxHexDisplay_clicked(bool checked) { if(checked) //如果打勾 { //1.读取textEdit内容 QString tmp = ui->textEditRev->toPlainText(); //2.转换成hex(因为QByteArray有toHex(),所以转换成QByteArray) QByteArray qtmp = tmp.toUtf8(); //因为QSrting没有把小写字母a转化成61的能力,QByteArray有,所以用QByteArray qtmp = qtmp.toHex(); //3.显示 QString lastShow; tmp = QString::fromUtf8(qtmp); //把QByteArray转换成QString格式 for(int i = 0; itextEditRev->setText(lastShow.toUpper()); //转换成大写 } else { //1.读取textEdit内容,hex QString tmpHexString = ui->textEditRev->toPlainText(); //2.将 QString 转换为 QByteArray QByteArray tmpHexQBytearray = tmpHexString.toUtf8(); //3.将十六进制字符串转换为字节数组 QByteArray tmpQByteString = QByteArray::fromHex(tmpHexQBytearray); //将61转换成a //4.显示 ui->textEditRev->setText(QString::fromUtf8(tmpQByteString)); } } void Widget::on_btnhideTable_clicked(bool checked) { if(checked) { ui->btnhideTable->setText("拓展面板"); ui->groupBoxTexts->hide(); //隐藏 } else { ui->btnhideTable->setText("隐藏面板"); ui->groupBoxTexts->show(); //展示 } } void Widget::on_btnHideHistory_clicked(bool checked) { if(checked) { ui->btnHideHistory->setText("显示历史"); ui->groupBoxRecord->hide(); //隐藏 } else { ui->btnHideHistory->setText("隐藏历史"); ui->groupBoxRecord->show(); //展示 } } //刷新串口号 void Widget::refreshSerialName() { ui->comboBox_serialnum->clear(); //清空comboBox QList serialList= QSerialPortInfo::availablePorts(); //获取系统中可用的串口 for(QSerialPortInfo serialInfo : serialList) //遍历serialList中所有可用串口 { qDebug() << serialInfo.portName(); ui->comboBox_serialnum->addItem(serialInfo.portName()); //将serialInfo对象所代表的串口添加到UI中 } ui->labelSendStatus->setText("Com Refresh"); } //固定文本发送,1,2,3 void Widget::on_command_button_clicked() { QPushButton *btn = qobject_cast(sender()); //将 sender() 返回的对象转换为 QPushButton* 指针 if(btn) { int num = btn->property("buttonId").toInt(); //获取按钮的 buttonId 属性并转换为整数 QString lineEditName = QString("lineEdit_%1").arg(num); //构造 QLineEdit 控件的名称 QLineEdit *lineEdit = findChild(lineEditName); //查找名为 lineEditName 的 QLineEdit 控件 if(lineEdit) { ui->lineEditSendContex->setText(lineEdit->text()); //将QLineEdit 控件的内容设置到 ui->lineEditSendContex 中 } QString checkBoxName = QString("checkBox_%1").arg(num); //构造 QCheckBox 控件的名称 QCheckBox * checkBox = findChild(checkBoxName); //查找对应的 QCheckBox 控件 if(checkBox) ui->checkBHexSend->setChecked(checkBox->isChecked()); //将找到的 QCheckBox 控件的状态设置到 checkBHexSend 中 on_btnSendContex_clicked(); //发送文本 } } ``` #### 串口调试助手定时器实现循环发送 Widget.h ``` #ifndef WIDGET_H #define WIDGET_H #include #include #include #include "mycombobox.h" QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private slots: void on_btncloseorOpen_clicked(bool checked); //打开或关闭串口 void on_btnSendContex_clicked(); //发送数据 void on_SerialData_readyToRead(); //准备去读数据 void on_checkBoxSendInTime_clicked(bool checked); //定时发送 void on_btnrevClear_clicked(); //接收清楚 void on_btnrevSave_clicked(); //保存接收 void time_reflash(); //更新系统时间 void on_checkBoxHexDisplay_clicked(bool checked); //Hex显示 void on_btnhideTable_clicked(bool checked); //隐藏面板 void on_btnHideHistory_clicked(bool checked); //隐藏历史 void refreshSerialName(); //刷新串口名字 void on_command_button_clicked(); //序号被点击 void on_checkBox_send_clicked(bool checked); void buttons_handler(); private: QSerialPort *serialPort; //声明一个对象,串口 int writeCntTotal; //统计发送了多少字节 int readCntTotal; //统计发送了多少字节 QString SendBack; //返回上一次输入的数据 QString MyTime; //系统时间 bool serialStatus; //确认状态 QTimer *timer; //定时发送 void getSysTime(); //获取系统时间 QTimer *buttonConTimer; // int buttonIndex; QList buttons; Ui::Widget *ui; }; #endif // WIDGET_H ``` Widget.cpp ``` #include "widget.h" #include "ui_widget.h" #include #include #include #include #include #include #include Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); this->setLayout(ui->gridLayoutGlobal); //让界面随着窗口变幻大小 ui->btnSendContex->setEnabled(false); //刚打开串口,发送按钮是失效的 ui->checkBoxSendInTime->setEnabled(false); //刚打开串口界面,定时发送选择框是失效的 ui->checkBoxrevTime->setEnabled(false); //刚打开串口界面,接收时间选择框是失效的 serialPort = new QSerialPort(this); //创建一个QSerialPort对象,将指针赋值给serialPort变量 QTimer *getSysTimeTimer = new QTimer(this); //创建一个QTimer对象,将指针赋值给getSysTimeTimer connect(getSysTimeTimer,SIGNAL(timeout()),this,SLOT(time_reflash())); getSysTimeTimer->start(100); //启动定时器,每隔100毫秒触发一次timeout信号 timer = new QTimer(this); //创建一个时间对象 buttonConTimer = new QTimer(this); //定时器 connect(buttonConTimer,&QTimer::timeout,this, &Widget::buttons_handler); //控制参数初始化 buttonIndex = 0; writeCntTotal = 0; //写入字节数 readCntTotal = 0; //读取字节数 serialStatus = false; //失效状态 //控件初始化 ui->btnSendContex->setEnabled(false); //发送按钮失效 ui->checkBoxSendInTime->setEnabled(false); //定时发送按钮失效 ui->checkSendNewLine->setEnabled(false); //发送新行失效 ui->checkBHexSend->setEnabled(false); //HEX发送失效 connect(timer,&QTimer::timeout,this,[=](){ on_btnSendContex_clicked(); }); //连接信号与槽,到点就发送文本 connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_SerialData_readyToRead); //连接函数,当接收数据可读时 connect(ui->comboBox_serialnum,&MyComboBox::refresh,this,&Widget::refreshSerialName); ui->comboBox_boautrate->setCurrentIndex(6); //将波特率索引值设置为6,方便选择 ui->comboBox_databit->setCurrentIndex(3); //将数据位索引值设置为3,方便选择 refreshSerialName(); ui->labelSendStatus->setText(ui->comboBox_serialnum->itemText(0)+" " + "NoOpen"); //状态文本初始化 for(int i = 1; i<=9; i++) { QString btnName = QString("pushButton_%1").arg(i); //从1到9 QPushButton* btn = findChild (btnName); if(btn) { btn->setProperty("buttonId",i); buttons.append(btn); connect(btn,SIGNAL(clicked()),this,SLOT(on_command_button_clicked())); } } } Widget::~Widget() { delete ui; } //打开或关闭串口 void Widget::on_btncloseorOpen_clicked(bool checked) { if(checked) { //1.选择端口号 serialPort->setPortName(ui->comboBox_serialnum->currentText()); //获取串口,把串口显示到文本上 //2.配置波特率 serialPort->setBaudRate(ui->comboBox_boautrate->currentText().toInt()); //显示波特率,转整型 //3.配置数据位 serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_databit->currentText().toInt())); //显示波特率,转整型 //4.配置校验位 switch (ui->comboBox_jiaoyan->currentText().toInt()) //用户选择校验位,并转为整型 { 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; } //5.配置停止位 serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_stopbit->currentText().toInt())); //显示停止位,转整型 //6.流控 if(ui->comboBox_fluidCon->currentText() == "None") //用户选择了None { serialPort->setFlowControl(QSerialPort::NoFlowControl); //执行,无流控 } //7.打开串口 if(serialPort->open(QIODevice::ReadWrite)) { qDebug() << "serial open success"; ui->comboBox_databit->setEnabled(false); //成功打开串口,这些按钮就失效 ui->comboBox_fluidCon->setEnabled(false); ui->comboBox_jiaoyan->setEnabled(false); ui->comboBox_stopbit->setEnabled(false); ui->comboBox_boautrate->setEnabled(false); ui->comboBox_serialnum->setEnabled(false); ui->btncloseorOpen->setText("关闭串口"); ui->btnSendContex->setEnabled(true); ui->checkBoxSendInTime->setEnabled(true); //成功打开串口,定时发送按钮生效 ui->checkSendNewLine->setEnabled(true); //发送新行生效 ui->checkBHexSend->setEnabled(true); //HEX发送生效 ui->labelSendStatus->setText(ui->comboBox_serialnum->currentText() + " " + "isOpen"); } else { qDebug() << "error"; QMessageBox msgBox; //弹窗 msgBox.setWindowTitle("打开串口错误"); msgBox.setText("打开失败,串口可能被占用或已拔出"); msgBox.exec(); } } else { serialPort->close(); ui->btncloseorOpen->setText("打开串口"); ui->comboBox_databit->setEnabled(true); //没有打开串口,这些按钮都是生效的 ui->comboBox_fluidCon->setEnabled(true); ui->comboBox_jiaoyan->setEnabled(true); ui->comboBox_stopbit->setEnabled(true); ui->comboBox_boautrate->setEnabled(true); ui->comboBox_serialnum->setEnabled(true); //serialStatus = false; ui->btnSendContex->setEnabled(false); //没有打开串口,发送按钮失效 ui->checkBoxSendInTime->setEnabled(false); //打开串口失败,定时发送按钮失效 ui->checkBoxSendInTime->setCheckState(Qt::Unchecked); //设置复选框为未选中状态 //关闭定时器 timer->stop(); ui->lineEditTimeeach->setEnabled(true); ui->lineEditSendContex->setEnabled(true); ui->checkSendNewLine->setEnabled(false); //发送新行失效 ui->checkBHexSend->setEnabled(false); //HEX发送失效 ui->labelSendStatus->setText(ui->comboBox_serialnum->currentText() + " " + "isClose"); } } //发送数据 void Widget::on_btnSendContex_clicked() { int writeCnt = 0; const char* sendData = ui->lineEditSendContex->text().toLocal8Bit().constData(); //把发送文本转换为C字符串指针 if(ui->checkBHexSend->isChecked()) //判断按键是否被按下 { QString tmp = ui->lineEditSendContex->text().toLocal8Bit().constData(); //判断是否是偶数位,16进制是两位 QByteArray tmpArray = tmp.toLocal8Bit(); if(tmpArray.size() % 2 != 0) { ui->labelSendStatus->setText("Error Input"); } //判断是否符合16进制的表达 for(char c : tmpArray) //定义一个c,遍历tmpArray数组 { if(!std::isxdigit(c)) //判断每一位是不是十六进制 { ui->labelSendStatus->setText("Error Input"); return; } } //转换成16进制发送,用户输入1,变成1,不会变成字符1,ASCII码 QByteArray arraySend = QByteArray::fromHex(tmpArray); //发送16进制 writeCnt = serialPort->write(arraySend); } else { //如果不是16进制发送 if(ui->checkSendNewLine->isChecked()) { QByteArray arraySendData(sendData,strlen(sendData)); arraySendData.append("\r\n"); writeCnt = serialPort->write(arraySendData); //返回实际写入的字节数 } else { writeCnt = serialPort->write(sendData); //返回实际写入的字节数 } } //发送失败清空 if(writeCnt == -1) { ui->labelSendStatus->setText("Send Error!"); //返回字节数失败,表示发送错误 } else { writeCntTotal += writeCnt; //写入成功,将字节数累加到writeCntTotal变量上 qDebug() << "SendOK" << sendData; //输出SendOK和sendData里面的内容 ui->labelSendStatus->setText("Send OK!"); //把发送状态改为Send OK ui->labelSendcnt->setNum(writeCntTotal); if(strcmp(sendData,SendBack.toStdString().c_str()) != 0) //比较sendData和上一次输出的数据是否相同 { ui->textEditRecord->append(sendData); //不同则在textEditRecord里追加数据 SendBack = QString::fromUtf8(sendData); //将数据转成QString类型,以便下次使用 } } } //读取发送的数据 void Widget::on_SerialData_readyToRead() { QString revMessage = serialPort->readAll(); //读取数据存于revMessage // qDebug() << "revCnt" << revMessage.size() << "context:" << revMessage; if(revMessage != NULL) //检查指针 revMessage 是否为非空指针,读取数据不为空 { if(ui->checkBLine->isChecked()) { revMessage.append("\r\n"); } //16进制显示 if(ui->checkBoxHexDisplay->isChecked()) //判断Hex显示是否被勾选 { QByteArray tmpHexString = revMessage.toUtf8().toHex().toUpper(); //原来控件上的内容,hex QString tmpStringHex = ui->textEditRev->toPlainText(); //因为勾选了,读出来就是Hex tmpHexString = tmpStringHex.toUtf8() + tmpHexString; //把读出的就的hex和新收到的数据转成hex进行拼接 ui->textEditRev->setText(QString::fromUtf8(tmpHexString)); //重新显示在控件上 } //非十六进制显示 else { if(ui->checkBoxrevTime->isChecked()) { getSysTime(); QString message = ui->lineEditSendContex->text() + " " + "【"+MyTime+"】"; ui->textEditRev->insertPlainText(message); } else { ui->textEditRev->insertPlainText(revMessage); //将收到的内容追加到textEditRev文本框中 } } } readCntTotal += revMessage.size(); //接收的总字节数 ui->labelRevcnt->setNum(readCntTotal); //计算接收到的字节数 } //自动发送 void Widget::on_checkBoxSendInTime_clicked(bool checked) { // qDebug() <<"checkBsendIntime" << checked; if(checked) //检测复选框是否被选中 { ui->lineEditTimeeach->setEnabled(false); //定时发送开始,定时文本无效 ui->lineEditTimeeach->setEnabled(false); //定时发送开始,发送文本无效 timer->start(1000); //启动定时器 timer->start(ui->lineEditTimeeach->text().toInt()); //允许用户修改时间间隔 //on_btnSendContex_clicked(); } else { timer->stop(); //停止定时器 ui->lineEditTimeeach->setEnabled(true); //定时器停止后,定时文本变有效 ui->lineEditSendContex->setEnabled(true); //定时器停止后,发送文本变有效 } } //清空接收 void Widget::on_btnrevClear_clicked() { ui->textEditRev->setText(""); //清空接收内容 } //保存接收内容 void Widget::on_btnrevSave_clicked() { QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "L:/QTproject/QT/serialData.txt", tr("Text (*.txt)")); //弹出文件选择框,保存文件 if(fileName != NULL) { QFile file(fileName); //创建一个 QFile 对象,用于操作文件 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return; //打开文件失败,则直接返回 } QTextStream out(&file); //创建一个QTextStream 对象,用于将数据写入文件 out <textEditRev->toPlainText(); //获取文本内容,输出到流out file.close(); //关闭文件 } } //更新串口调试助手时间 void Widget::time_reflash() { getSysTime(); ui->labelCurrentTime->setText(MyTime); } //获取系统时间 void Widget::getSysTime() { QDateTime currentTime = QDateTime::currentDateTime(); //创建一个currentTime对象,返回当前系统时间 QDate date = currentTime.date(); //返回一个日期对象date int year = date.year(); //获取年份,存储在year变量中 int month = date.month(); //获取月份,存储在month变量中 int day = date.day(); //获取日,存储在day变量中 QTime time = currentTime.time(); //创建一个time对象,返回时间 int hour = time.hour(); //获取时,存储在hour变量中 int minute = time.minute(); //获取时,存储在minute变量中 int second = time.second(); //获取时,存储在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')); } //Hex显示 void Widget::on_checkBoxHexDisplay_clicked(bool checked) { if(checked) //如果打勾 { //1.读取textEdit内容 QString tmp = ui->textEditRev->toPlainText(); //2.转换成hex(因为QByteArray有toHex(),所以转换成QByteArray) QByteArray qtmp = tmp.toUtf8(); //因为QSrting没有把小写字母a转化成61的能力,QByteArray有,所以用QByteArray qtmp = qtmp.toHex(); //3.显示 QString lastShow; tmp = QString::fromUtf8(qtmp); //把QByteArray转换成QString格式 for(int i = 0; itextEditRev->setText(lastShow.toUpper()); //转换成大写 } else { //1.读取textEdit内容,hex QString tmpHexString = ui->textEditRev->toPlainText(); //2.将 QString 转换为 QByteArray QByteArray tmpHexQBytearray = tmpHexString.toUtf8(); //3.将十六进制字符串转换为字节数组 QByteArray tmpQByteString = QByteArray::fromHex(tmpHexQBytearray); //将61转换成a //4.显示 ui->textEditRev->setText(QString::fromUtf8(tmpQByteString)); } } void Widget::on_btnhideTable_clicked(bool checked) { if(checked) { ui->btnhideTable->setText("拓展面板"); ui->groupBoxTexts->hide(); //隐藏 } else { ui->btnhideTable->setText("隐藏面板"); ui->groupBoxTexts->show(); //展示 } } void Widget::on_btnHideHistory_clicked(bool checked) { if(checked) { ui->btnHideHistory->setText("显示历史"); ui->groupBoxRecord->hide(); //隐藏 } else { ui->btnHideHistory->setText("隐藏历史"); ui->groupBoxRecord->show(); //展示 } } //刷新串口号 void Widget::refreshSerialName() { ui->comboBox_serialnum->clear(); //清空comboBox QList serialList= QSerialPortInfo::availablePorts(); //获取系统中可用的串口 for(QSerialPortInfo serialInfo : serialList) //遍历所有可用串口 { qDebug() << serialInfo.portName(); ui->comboBox_serialnum->addItem(serialInfo.portName()); //将serialInfo对象所代表的串口添加到UI中 } ui->labelSendStatus->setText("Com Refresh"); } //指令发送,1,2,3 void Widget::on_command_button_clicked() { QPushButton *btn = qobject_cast(sender()); if(btn) { int num = btn->property("buttonId").toInt(); QString lineEditName = QString("lineEdit_%1").arg(num); QLineEdit *lineEdit = findChild(lineEditName); if(lineEdit) { ui->lineEditSendContex->setText(lineEdit->text()); } QString checkBoxName = QString("checkBox_%1").arg(num); QCheckBox * checkBox = findChild(checkBoxName); if(checkBox) ui->checkBHexSend->setChecked(checkBox->isChecked()); on_btnSendContex_clicked(); //发送文本 } } //发送序号 void Widget::buttons_handler() { // 检查 buttonIndex 是否小于 buttons 列表的大小(最多 9 个按钮) if(buttonIndex < buttons.size()) { QPushButton* btnTmp = buttons[buttonIndex]; // 获取当前索引对应的按钮 emit btnTmp->clicked(); // 发射该按钮的 clicked 信号 buttonIndex++; // 增加 buttonIndex,以便下次调用时处理下一个按钮 } else { buttonIndex = 0; // 如果 buttonIndex 已经达到 buttons 列表的大小,重置 buttonIndex 为 0 } } //循环发送 void Widget::on_checkBox_send_clicked(bool checked) { // 当复选框被选中时 if(checked) { // 启动定时器,并设置间隔时间 // 从 spinBox 中获取间隔时间(以毫秒为单位),并将其转换为无符号整数 buttonConTimer->start(ui->spinBox->text().toUInt()); } else // 当复选框未被选中时 { buttonConTimer->stop(); //停止定时器 } } ``` #### 串口调试助手线程实现循环发送 Widget.h ``` #ifndef WIDGET_H #define WIDGET_H #include #include #include #include "mycombobox.h" #include "customthread.h" QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private slots: void on_btncloseorOpen_clicked(bool checked); //打开或关闭串口 void on_btnSendContex_clicked(); //发送数据 void on_SerialData_readyToRead(); //准备去读数据 void on_checkBoxSendInTime_clicked(bool checked); //定时发送 void on_btnrevClear_clicked(); //接收清楚 void on_btnrevSave_clicked(); //保存接收 void time_reflash(); //更新系统时间 void on_checkBoxHexDisplay_clicked(bool checked); //Hex显示 void on_btnhideTable_clicked(bool checked); //隐藏面板 void on_btnHideHistory_clicked(bool checked); //隐藏历史 void refreshSerialName(); //刷新串口名字 void on_command_button_clicked(); //序号被点击 void on_checkBox_send_clicked(bool checked); void buttons_handler(); private: QSerialPort *serialPort; //声明一个对象,串口 int writeCntTotal; //统计发送了多少字节 int readCntTotal; //统计发送了多少字节 QString SendBack; //返回上一次输入的数据 QString MyTime; //系统时间 bool serialStatus; //确认状态 QTimer *timer; //定时发送 void getSysTime(); //获取系统时间 QTimer *buttonConTimer; // int buttonIndex; CustomThread *mythread; QList buttons; Ui::Widget *ui; }; #endif // WIDGET_H ``` customthread.h ``` #ifndef CUSTOMTHREAD_H #define CUSTOMTHREAD_H #include #include //定义一个名为 CustomThread 的类,继承自 QThread class CustomThread : public QThread { Q_OBJECT //启用 Qt 的元对象系统 protected: void run() override; // 重写 run 方法 public: CustomThread(QWidget *parent); //构造函数 signals: void threadTimeout(); //定时器超时信号 }; #endif // CUSTOMTHREAD_H ``` Widget.cpp ``` #include "widget.h" #include "ui_widget.h" #include #include #include #include #include #include #include Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); this->setLayout(ui->gridLayoutGlobal); //让界面随着窗口变幻大小 ui->btnSendContex->setEnabled(false); //刚打开串口,发送按钮是失效的 ui->checkBoxSendInTime->setEnabled(false); //刚打开串口界面,定时发送选择框是失效的 ui->checkBoxrevTime->setEnabled(false); //刚打开串口界面,接收时间选择框是失效的 serialPort = new QSerialPort(this); //创建一个QSerialPort对象,将指针赋值给serialPort变量 QTimer *getSysTimeTimer = new QTimer(this); //创建一个QTimer对象,将指针赋值给getSysTimeTimer connect(getSysTimeTimer,SIGNAL(timeout()),this,SLOT(time_reflash())); getSysTimeTimer->start(100); //启动定时器,每隔100毫秒触发一次timeout信号 timer = new QTimer(this); //创建一个时间对象 // buttonConTimer = new QTimer(this); //定时器 // connect(buttonConTimer,&QTimer::timeout,this, &Widget::buttons_handler); mythread = new CustomThread(this); //线程 connect(mythread,&CustomThread::threadTimeout,this,&Widget::buttons_handler); //控制参数初始化 buttonIndex = 0; writeCntTotal = 0; //写入字节数 readCntTotal = 0; //读取字节数 serialStatus = false; //失效状态 //控件初始化 ui->btnSendContex->setEnabled(false); //发送按钮失效 ui->checkBoxSendInTime->setEnabled(false); //定时发送按钮失效 ui->checkSendNewLine->setEnabled(false); //发送新行失效 ui->checkBHexSend->setEnabled(false); //HEX发送失效 connect(timer,&QTimer::timeout,this,[=](){ on_btnSendContex_clicked(); }); //连接信号与槽,到点就发送文本 connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_SerialData_readyToRead); //连接函数,当接收数据可读时 connect(ui->comboBox_serialnum,&MyComboBox::refresh,this,&Widget::refreshSerialName); ui->comboBox_boautrate->setCurrentIndex(6); //将波特率索引值设置为6,方便选择 ui->comboBox_databit->setCurrentIndex(3); //将数据位索引值设置为3,方便选择 refreshSerialName(); ui->labelSendStatus->setText(ui->comboBox_serialnum->itemText(0)+" " + "NoOpen"); //状态文本初始化 for(int i = 1; i<=9; i++) { QString btnName = QString("pushButton_%1").arg(i); //从1到9 QPushButton* btn = findChild (btnName); if(btn) { btn->setProperty("buttonId",i); buttons.append(btn); connect(btn,SIGNAL(clicked()),this,SLOT(on_command_button_clicked())); } } } Widget::~Widget() { delete ui; } //打开或关闭串口 void Widget::on_btncloseorOpen_clicked(bool checked) { if(checked) { //1.选择端口号 serialPort->setPortName(ui->comboBox_serialnum->currentText()); //获取串口,把串口显示到文本上 //2.配置波特率 serialPort->setBaudRate(ui->comboBox_boautrate->currentText().toInt()); //显示波特率,转整型 //3.配置数据位 serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_databit->currentText().toInt())); //显示波特率,转整型 //4.配置校验位 switch (ui->comboBox_jiaoyan->currentText().toInt()) //用户选择校验位,并转为整型 { 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; } //5.配置停止位 serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_stopbit->currentText().toInt())); //显示停止位,转整型 //6.流控 if(ui->comboBox_fluidCon->currentText() == "None") //用户选择了None { serialPort->setFlowControl(QSerialPort::NoFlowControl); //执行,无流控 } //7.打开串口 if(serialPort->open(QIODevice::ReadWrite)) { qDebug() << "serial open success"; ui->comboBox_databit->setEnabled(false); //成功打开串口,这些按钮就失效 ui->comboBox_fluidCon->setEnabled(false); ui->comboBox_jiaoyan->setEnabled(false); ui->comboBox_stopbit->setEnabled(false); ui->comboBox_boautrate->setEnabled(false); ui->comboBox_serialnum->setEnabled(false); ui->btncloseorOpen->setText("关闭串口"); ui->btnSendContex->setEnabled(true); ui->checkBoxSendInTime->setEnabled(true); //成功打开串口,定时发送按钮生效 ui->checkSendNewLine->setEnabled(true); //发送新行生效 ui->checkBHexSend->setEnabled(true); //HEX发送生效 ui->labelSendStatus->setText(ui->comboBox_serialnum->currentText() + " " + "isOpen"); } else { qDebug() << "error"; QMessageBox msgBox; //弹窗 msgBox.setWindowTitle("打开串口错误"); msgBox.setText("打开失败,串口可能被占用或已拔出"); msgBox.exec(); } } else { serialPort->close(); ui->btncloseorOpen->setText("打开串口"); ui->comboBox_databit->setEnabled(true); //没有打开串口,这些按钮都是生效的 ui->comboBox_fluidCon->setEnabled(true); ui->comboBox_jiaoyan->setEnabled(true); ui->comboBox_stopbit->setEnabled(true); ui->comboBox_boautrate->setEnabled(true); ui->comboBox_serialnum->setEnabled(true); //serialStatus = false; ui->btnSendContex->setEnabled(false); //没有打开串口,发送按钮失效 ui->checkBoxSendInTime->setEnabled(false); //打开串口失败,定时发送按钮失效 ui->checkBoxSendInTime->setCheckState(Qt::Unchecked); //设置复选框为未选中状态 //关闭定时器 timer->stop(); ui->lineEditTimeeach->setEnabled(true); ui->lineEditSendContex->setEnabled(true); ui->checkSendNewLine->setEnabled(false); //发送新行失效 ui->checkBHexSend->setEnabled(false); //HEX发送失效 ui->labelSendStatus->setText(ui->comboBox_serialnum->currentText() + " " + "isClose"); } } //发送数据 void Widget::on_btnSendContex_clicked() { int writeCnt = 0; const char* sendData = ui->lineEditSendContex->text().toLocal8Bit().constData(); //把发送文本转换为C字符串指针 if(ui->checkBHexSend->isChecked()) //判断按键是否被按下 { QString tmp = ui->lineEditSendContex->text().toLocal8Bit().constData(); //判断是否是偶数位,16进制是两位 QByteArray tmpArray = tmp.toLocal8Bit(); if(tmpArray.size() % 2 != 0) { ui->labelSendStatus->setText("Error Input"); } //判断是否符合16进制的表达 for(char c : tmpArray) //定义一个c,遍历tmpArray数组 { if(!std::isxdigit(c)) //判断每一位是不是十六进制 { ui->labelSendStatus->setText("Error Input"); return; } } //转换成16进制发送,用户输入1,变成1,不会变成字符1,ASCII码 QByteArray arraySend = QByteArray::fromHex(tmpArray); //发送16进制 writeCnt = serialPort->write(arraySend); } else { //如果不是16进制发送 if(ui->checkSendNewLine->isChecked()) { QByteArray arraySendData(sendData,strlen(sendData)); arraySendData.append("\r\n"); writeCnt = serialPort->write(arraySendData); //返回实际写入的字节数 } else { writeCnt = serialPort->write(sendData); //返回实际写入的字节数 } } //发送失败清空 if(writeCnt == -1) { ui->labelSendStatus->setText("Send Error!"); //返回字节数失败,表示发送错误 } else { writeCntTotal += writeCnt; //写入成功,将字节数累加到writeCntTotal变量上 qDebug() << "SendOK" << sendData; //输出SendOK和sendData里面的内容 ui->labelSendStatus->setText("Send OK!"); //把发送状态改为Send OK ui->labelSendcnt->setNum(writeCntTotal); if(strcmp(sendData,SendBack.toStdString().c_str()) != 0) //比较sendData和上一次输出的数据是否相同 { ui->textEditRecord->append(sendData); //不同则在textEditRecord里追加数据 SendBack = QString::fromUtf8(sendData); //将数据转成QString类型,以便下次使用 } } } //读取发送的数据 void Widget::on_SerialData_readyToRead() { QString revMessage = serialPort->readAll(); //读取数据存于revMessage // qDebug() << "revCnt" << revMessage.size() << "context:" << revMessage; if(revMessage != NULL) //检查指针 revMessage 是否为非空指针,读取数据不为空 { if(ui->checkBLine->isChecked()) { revMessage.append("\r\n"); } //16进制显示 if(ui->checkBoxHexDisplay->isChecked()) //判断Hex显示是否被勾选 { QByteArray tmpHexString = revMessage.toUtf8().toHex().toUpper(); //原来控件上的内容,hex QString tmpStringHex = ui->textEditRev->toPlainText(); //因为勾选了,读出来就是Hex tmpHexString = tmpStringHex.toUtf8() + tmpHexString; //把读出的就的hex和新收到的数据转成hex进行拼接 ui->textEditRev->setText(QString::fromUtf8(tmpHexString)); //重新显示在控件上 } //非十六进制显示 else { if(ui->checkBoxrevTime->isChecked()) { getSysTime(); QString message = ui->lineEditSendContex->text() + " " + "【"+MyTime+"】"; ui->textEditRev->insertPlainText(message); } else { ui->textEditRev->insertPlainText(revMessage); //将收到的内容追加到textEditRev文本框中 } } } readCntTotal += revMessage.size(); //接收的总字节数 ui->labelRevcnt->setNum(readCntTotal); //计算接收到的字节数 } //自动发送 void Widget::on_checkBoxSendInTime_clicked(bool checked) { // qDebug() <<"checkBsendIntime" << checked; if(checked) //检测复选框是否被选中 { ui->lineEditTimeeach->setEnabled(false); //定时发送开始,定时文本无效 ui->lineEditTimeeach->setEnabled(false); //定时发送开始,发送文本无效 timer->start(1000); //启动定时器 timer->start(ui->lineEditTimeeach->text().toInt()); //允许用户修改时间间隔 //on_btnSendContex_clicked(); } else { timer->stop(); //停止定时器 ui->lineEditTimeeach->setEnabled(true); //定时器停止后,定时文本变有效 ui->lineEditSendContex->setEnabled(true); //定时器停止后,发送文本变有效 } } //清空接收 void Widget::on_btnrevClear_clicked() { ui->textEditRev->setText(""); //清空接收内容 } //保存接收内容 void Widget::on_btnrevSave_clicked() { QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "L:/QTproject/QT/serialData.txt", tr("Text (*.txt)")); //弹出文件选择框,保存文件 if(fileName != NULL) { QFile file(fileName); //创建一个 QFile 对象,用于操作文件 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return; //打开文件失败,则直接返回 } QTextStream out(&file); //创建一个QTextStream 对象,用于将数据写入文件 out <textEditRev->toPlainText(); //获取文本内容,输出到流out file.close(); //关闭文件 } } //更新串口调试助手时间 void Widget::time_reflash() { getSysTime(); ui->labelCurrentTime->setText(MyTime); } //获取系统时间 void Widget::getSysTime() { QDateTime currentTime = QDateTime::currentDateTime(); //创建一个currentTime对象,返回当前系统时间 QDate date = currentTime.date(); //返回一个日期对象date int year = date.year(); //获取年份,存储在year变量中 int month = date.month(); //获取月份,存储在month变量中 int day = date.day(); //获取日,存储在day变量中 QTime time = currentTime.time(); //创建一个time对象,返回时间 int hour = time.hour(); //获取时,存储在hour变量中 int minute = time.minute(); //获取时,存储在minute变量中 int second = time.second(); //获取时,存储在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')); } //Hex显示 void Widget::on_checkBoxHexDisplay_clicked(bool checked) { if(checked) //如果打勾 { //1.读取textEdit内容 QString tmp = ui->textEditRev->toPlainText(); //2.转换成hex(因为QByteArray有toHex(),所以转换成QByteArray) QByteArray qtmp = tmp.toUtf8(); //因为QSrting没有把小写字母a转化成61的能力,QByteArray有,所以用QByteArray qtmp = qtmp.toHex(); //3.显示 QString lastShow; tmp = QString::fromUtf8(qtmp); //把QByteArray转换成QString格式 for(int i = 0; itextEditRev->setText(lastShow.toUpper()); //转换成大写 } else { //1.读取textEdit内容,hex QString tmpHexString = ui->textEditRev->toPlainText(); //2.将 QString 转换为 QByteArray QByteArray tmpHexQBytearray = tmpHexString.toUtf8(); //3.将十六进制字符串转换为字节数组 QByteArray tmpQByteString = QByteArray::fromHex(tmpHexQBytearray); //将61转换成a //4.显示 ui->textEditRev->setText(QString::fromUtf8(tmpQByteString)); } } void Widget::on_btnhideTable_clicked(bool checked) { if(checked) { ui->btnhideTable->setText("拓展面板"); ui->groupBoxTexts->hide(); //隐藏 } else { ui->btnhideTable->setText("隐藏面板"); ui->groupBoxTexts->show(); //展示 } } void Widget::on_btnHideHistory_clicked(bool checked) { if(checked) { ui->btnHideHistory->setText("显示历史"); ui->groupBoxRecord->hide(); //隐藏 } else { ui->btnHideHistory->setText("隐藏历史"); ui->groupBoxRecord->show(); //展示 } } //刷新串口号 void Widget::refreshSerialName() { ui->comboBox_serialnum->clear(); //清空comboBox QList serialList= QSerialPortInfo::availablePorts(); //获取系统中可用的串口 for(QSerialPortInfo serialInfo : serialList) //遍历所有可用串口 { qDebug() << serialInfo.portName(); ui->comboBox_serialnum->addItem(serialInfo.portName()); //将serialInfo对象所代表的串口添加到UI中 } ui->labelSendStatus->setText("Com Refresh"); } //指令发送,1,2,3 void Widget::on_command_button_clicked() { QPushButton *btn = qobject_cast(sender()); if(btn) { int num = btn->property("buttonId").toInt(); QString lineEditName = QString("lineEdit_%1").arg(num); QLineEdit *lineEdit = findChild(lineEditName); if(lineEdit) { ui->lineEditSendContex->setText(lineEdit->text()); } QString checkBoxName = QString("checkBox_%1").arg(num); QCheckBox * checkBox = findChild(checkBoxName); if(checkBox) ui->checkBHexSend->setChecked(checkBox->isChecked()); on_btnSendContex_clicked(); //发送文本 } } void Widget::buttons_handler() { if(buttonIndex < buttons.size()) { QPushButton* btnTmp = buttons[buttonIndex]; emit btnTmp->clicked(); buttonIndex++; } else { buttonIndex = 0; } } void Widget::on_checkBox_send_clicked(bool checked) { // 当复选框被选中时 if(checked) { ui->spinBox->setEnabled(false); // 禁用 spinBox 控件,防止用户在定时器运行时修改间隔时间 mythread->start(); // 启动自定义线程 } // 当复选框未被选中时 // 重新启用 spinBox 控件 else { ui->spinBox->setEnabled(true); // 重新启用 spinBox 控件 mythread->terminate(); //立即终止进程 } } ``` #### 串口调试助手重置文本 Widget.h ``` #ifndef WIDGET_H #define WIDGET_H #include #include #include #include #include "mycombobox.h" #include "customthread.h" QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private slots: void on_btncloseorOpen_clicked(bool checked); //打开或关闭串口 void on_btnSendContex_clicked(); //发送数据 void on_SerialData_readyToRead(); //准备去读数据 void on_checkBoxSendInTime_clicked(bool checked); //定时发送 void on_btnrevClear_clicked(); //接收清楚 void on_btnrevSave_clicked(); //保存接收 void time_reflash(); //更新系统时间 void on_checkBoxHexDisplay_clicked(bool checked); //Hex显示 void on_btnhideTable_clicked(bool checked); //隐藏面板 void on_btnHideHistory_clicked(bool checked); //隐藏历史 void refreshSerialName(); //刷新串口名字 void on_command_button_clicked(); //序号被点击 void on_checkBox_send_clicked(bool checked); void buttons_handler(); void on_btnInit_clicked(); private: QSerialPort *serialPort; //声明一个对象,串口 int writeCntTotal; //统计发送了多少字节 int readCntTotal; //统计发送了多少字节 QString SendBack; //返回上一次输入的数据 QString MyTime; //系统时间 bool serialStatus; //确认状态 QTimer *timer; //定时发送 void getSysTime(); //获取系统时间 QTimer *buttonConTimer; int buttonIndex; CustomThread *mythread; QList buttons; QList lineEdits; QList checkBoxs; Ui::Widget *ui; }; #endif // WIDGET_H ``` Widget.cpp ``` #include "widget.h" #include "ui_widget.h" #include #include #include #include #include #include #include Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); this->setLayout(ui->gridLayoutGlobal); //让界面随着窗口变幻大小 ui->btnSendContex->setEnabled(false); //刚打开串口,发送按钮是失效的 ui->checkBoxSendInTime->setEnabled(false); //刚打开串口界面,定时发送选择框是失效的 ui->checkBoxrevTime->setEnabled(false); //刚打开串口界面,接收时间选择框是失效的 serialPort = new QSerialPort(this); //创建一个QSerialPort对象,将指针赋值给serialPort变量 QTimer *getSysTimeTimer = new QTimer(this); //创建一个QTimer对象,将指针赋值给getSysTimeTimer connect(getSysTimeTimer,SIGNAL(timeout()),this,SLOT(time_reflash())); getSysTimeTimer->start(100); //启动定时器,每隔100毫秒触发一次timeout信号 timer = new QTimer(this); //创建一个时间对象 // buttonConTimer = new QTimer(this); //定时器 // connect(buttonConTimer,&QTimer::timeout,this, &Widget::buttons_handler); mythread = new CustomThread(this); //线程 connect(mythread,&CustomThread::threadTimeout,this,&Widget::buttons_handler); //控制参数初始化 buttonIndex = 0; writeCntTotal = 0; //写入字节数 readCntTotal = 0; //读取字节数 serialStatus = false; //失效状态 //控件初始化 ui->btnSendContex->setEnabled(false); //发送按钮失效 ui->checkBoxSendInTime->setEnabled(false); //定时发送按钮失效 ui->checkSendNewLine->setEnabled(false); //发送新行失效 ui->checkBHexSend->setEnabled(false); //HEX发送失效 connect(timer,&QTimer::timeout,this,[=](){ on_btnSendContex_clicked(); }); //连接信号与槽,到点就发送文本 connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_SerialData_readyToRead); //连接函数,当接收数据可读时 connect(ui->comboBox_serialnum,&MyComboBox::refresh,this,&Widget::refreshSerialName); ui->comboBox_boautrate->setCurrentIndex(6); //将波特率索引值设置为6,方便选择 ui->comboBox_databit->setCurrentIndex(3); //将数据位索引值设置为3,方便选择 refreshSerialName(); ui->labelSendStatus->setText(ui->comboBox_serialnum->itemText(0)+" " + "NoOpen"); //状态文本初始化 for(int i = 1; i<=9; i++) { QString btnName = QString("pushButton_%1").arg(i); //从1到9 QPushButton* btn = findChild (btnName); if(btn) { btn->setProperty("buttonId",i); buttons.append(btn); connect(btn,SIGNAL(clicked()),this,SLOT(on_command_button_clicked())); } QString lineEditName = QString("lineEdit_%1").arg(i); QLineEdit *lineEdit = findChild(lineEditName); lineEdits.append(lineEdit); QString checkBoxName = QString("checkBox_%1").arg(i); QCheckBox *checkBox = findChild(checkBoxName); checkBoxs.append(checkBox); } } Widget::~Widget() { delete ui; } //打开或关闭串口 void Widget::on_btncloseorOpen_clicked(bool checked) { if(checked) { //1.选择端口号 serialPort->setPortName(ui->comboBox_serialnum->currentText()); //获取串口,把串口显示到文本上 //2.配置波特率 serialPort->setBaudRate(ui->comboBox_boautrate->currentText().toInt()); //显示波特率,转整型 //3.配置数据位 serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_databit->currentText().toInt())); //显示波特率,转整型 //4.配置校验位 switch (ui->comboBox_jiaoyan->currentText().toInt()) //用户选择校验位,并转为整型 { 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; } //5.配置停止位 serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_stopbit->currentText().toInt())); //显示停止位,转整型 //6.流控 if(ui->comboBox_fluidCon->currentText() == "None") //用户选择了None { serialPort->setFlowControl(QSerialPort::NoFlowControl); //执行,无流控 } //7.打开串口 if(serialPort->open(QIODevice::ReadWrite)) { qDebug() << "serial open success"; ui->comboBox_databit->setEnabled(false); //成功打开串口,这些按钮就失效 ui->comboBox_fluidCon->setEnabled(false); ui->comboBox_jiaoyan->setEnabled(false); ui->comboBox_stopbit->setEnabled(false); ui->comboBox_boautrate->setEnabled(false); ui->comboBox_serialnum->setEnabled(false); ui->btncloseorOpen->setText("关闭串口"); ui->btnSendContex->setEnabled(true); ui->checkBoxSendInTime->setEnabled(true); //成功打开串口,定时发送按钮生效 ui->checkSendNewLine->setEnabled(true); //发送新行生效 ui->checkBHexSend->setEnabled(true); //HEX发送生效 ui->labelSendStatus->setText(ui->comboBox_serialnum->currentText() + " " + "isOpen"); } else { qDebug() << "error"; QMessageBox msgBox; //弹窗 msgBox.setWindowTitle("打开串口错误"); msgBox.setText("打开失败,串口可能被占用或已拔出"); msgBox.exec(); } } else { serialPort->close(); ui->btncloseorOpen->setText("打开串口"); ui->comboBox_databit->setEnabled(true); //没有打开串口,这些按钮都是生效的 ui->comboBox_fluidCon->setEnabled(true); ui->comboBox_jiaoyan->setEnabled(true); ui->comboBox_stopbit->setEnabled(true); ui->comboBox_boautrate->setEnabled(true); ui->comboBox_serialnum->setEnabled(true); //serialStatus = false; ui->btnSendContex->setEnabled(false); //没有打开串口,发送按钮失效 ui->checkBoxSendInTime->setEnabled(false); //打开串口失败,定时发送按钮失效 ui->checkBoxSendInTime->setCheckState(Qt::Unchecked); //设置复选框为未选中状态 //关闭定时器 timer->stop(); ui->lineEditTimeeach->setEnabled(true); ui->lineEditSendContex->setEnabled(true); ui->checkSendNewLine->setEnabled(false); //发送新行失效 ui->checkBHexSend->setEnabled(false); //HEX发送失效 ui->labelSendStatus->setText(ui->comboBox_serialnum->currentText() + " " + "isClose"); } } //发送数据 void Widget::on_btnSendContex_clicked() { int writeCnt = 0; const char* sendData = ui->lineEditSendContex->text().toLocal8Bit().constData(); //把发送文本转换为C字符串指针 if(ui->checkBHexSend->isChecked()) //判断按键是否被按下 { QString tmp = ui->lineEditSendContex->text().toLocal8Bit().constData(); //判断是否是偶数位,16进制是两位 QByteArray tmpArray = tmp.toLocal8Bit(); if(tmpArray.size() % 2 != 0) { ui->labelSendStatus->setText("Error Input"); } //判断是否符合16进制的表达 for(char c : tmpArray) //定义一个c,遍历tmpArray数组 { if(!std::isxdigit(c)) //判断每一位是不是十六进制 { ui->labelSendStatus->setText("Error Input"); return; } } //转换成16进制发送,用户输入1,变成1,不会变成字符1,ASCII码 QByteArray arraySend = QByteArray::fromHex(tmpArray); //发送16进制 writeCnt = serialPort->write(arraySend); } else { //如果不是16进制发送 if(ui->checkSendNewLine->isChecked()) { QByteArray arraySendData(sendData,strlen(sendData)); arraySendData.append("\r\n"); writeCnt = serialPort->write(arraySendData); //返回实际写入的字节数 } else { writeCnt = serialPort->write(sendData); //返回实际写入的字节数 } } //发送失败清空 if(writeCnt == -1) { ui->labelSendStatus->setText("Send Error!"); //返回字节数失败,表示发送错误 } else { writeCntTotal += writeCnt; //写入成功,将字节数累加到writeCntTotal变量上 qDebug() << "SendOK" << sendData; //输出SendOK和sendData里面的内容 ui->labelSendStatus->setText("Send OK!"); //把发送状态改为Send OK ui->labelSendcnt->setNum(writeCntTotal); if(strcmp(sendData,SendBack.toStdString().c_str()) != 0) //比较sendData和上一次输出的数据是否相同 { ui->textEditRecord->append(sendData); //不同则在textEditRecord里追加数据 SendBack = QString::fromUtf8(sendData); //将数据转成QString类型,以便下次使用 } } } //读取发送的数据 void Widget::on_SerialData_readyToRead() { QString revMessage = serialPort->readAll(); //读取数据存于revMessage // qDebug() << "revCnt" << revMessage.size() << "context:" << revMessage; if(revMessage != NULL) //检查指针 revMessage 是否为非空指针,读取数据不为空 { if(ui->checkBLine->isChecked()) { revMessage.append("\r\n"); } //16进制显示 if(ui->checkBoxHexDisplay->isChecked()) //判断Hex显示是否被勾选 { QByteArray tmpHexString = revMessage.toUtf8().toHex().toUpper(); //原来控件上的内容,hex QString tmpStringHex = ui->textEditRev->toPlainText(); //因为勾选了,读出来就是Hex tmpHexString = tmpStringHex.toUtf8() + tmpHexString; //把读出的就的hex和新收到的数据转成hex进行拼接 ui->textEditRev->setText(QString::fromUtf8(tmpHexString)); //重新显示在控件上 } //非十六进制显示 else { if(ui->checkBoxrevTime->isChecked()) { getSysTime(); QString message = ui->lineEditSendContex->text() + " " + "【"+MyTime+"】"; ui->textEditRev->insertPlainText(message); } else { ui->textEditRev->insertPlainText(revMessage); //将收到的内容追加到textEditRev文本框中 } } } readCntTotal += revMessage.size(); //接收的总字节数 ui->labelRevcnt->setNum(readCntTotal); //计算接收到的字节数 } //自动发送 void Widget::on_checkBoxSendInTime_clicked(bool checked) { // qDebug() <<"checkBsendIntime" << checked; if(checked) //检测复选框是否被选中 { ui->lineEditTimeeach->setEnabled(false); //定时发送开始,定时文本无效 ui->lineEditTimeeach->setEnabled(false); //定时发送开始,发送文本无效 timer->start(1000); //启动定时器 timer->start(ui->lineEditTimeeach->text().toInt()); //允许用户修改时间间隔 //on_btnSendContex_clicked(); } else { timer->stop(); //停止定时器 ui->lineEditTimeeach->setEnabled(true); //定时器停止后,定时文本变有效 ui->lineEditSendContex->setEnabled(true); //定时器停止后,发送文本变有效 } } //清空接收 void Widget::on_btnrevClear_clicked() { ui->textEditRev->setText(""); //清空接收内容 } //保存接收内容 void Widget::on_btnrevSave_clicked() { QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "L:/QTproject/QT/serialData.txt", tr("Text (*.txt)")); //弹出文件选择框,保存文件 if(fileName != NULL) { QFile file(fileName); //创建一个 QFile 对象,用于操作文件 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return; //打开文件失败,则直接返回 } QTextStream out(&file); //创建一个QTextStream 对象,用于将数据写入文件 out <textEditRev->toPlainText(); //获取文本内容,输出到流out file.close(); //关闭文件 } } //更新串口调试助手时间 void Widget::time_reflash() { getSysTime(); ui->labelCurrentTime->setText(MyTime); } //获取系统时间 void Widget::getSysTime() { QDateTime currentTime = QDateTime::currentDateTime(); //创建一个currentTime对象,返回当前系统时间 QDate date = currentTime.date(); //返回一个日期对象date int year = date.year(); //获取年份,存储在year变量中 int month = date.month(); //获取月份,存储在month变量中 int day = date.day(); //获取日,存储在day变量中 QTime time = currentTime.time(); //创建一个time对象,返回时间 int hour = time.hour(); //获取时,存储在hour变量中 int minute = time.minute(); //获取时,存储在minute变量中 int second = time.second(); //获取时,存储在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')); } //Hex显示 void Widget::on_checkBoxHexDisplay_clicked(bool checked) { if(checked) //如果打勾 { //1.读取textEdit内容 QString tmp = ui->textEditRev->toPlainText(); //2.转换成hex(因为QByteArray有toHex(),所以转换成QByteArray) QByteArray qtmp = tmp.toUtf8(); //因为QSrting没有把小写字母a转化成61的能力,QByteArray有,所以用QByteArray qtmp = qtmp.toHex(); //3.显示 QString lastShow; tmp = QString::fromUtf8(qtmp); //把QByteArray转换成QString格式 for(int i = 0; itextEditRev->setText(lastShow.toUpper()); //转换成大写 } else { //1.读取textEdit内容,hex QString tmpHexString = ui->textEditRev->toPlainText(); //2.将 QString 转换为 QByteArray QByteArray tmpHexQBytearray = tmpHexString.toUtf8(); //3.将十六进制字符串转换为字节数组 QByteArray tmpQByteString = QByteArray::fromHex(tmpHexQBytearray); //将61转换成a //4.显示 ui->textEditRev->setText(QString::fromUtf8(tmpQByteString)); } } void Widget::on_btnhideTable_clicked(bool checked) { if(checked) { ui->btnhideTable->setText("拓展面板"); ui->groupBoxTexts->hide(); //隐藏 } else { ui->btnhideTable->setText("隐藏面板"); ui->groupBoxTexts->show(); //展示 } } void Widget::on_btnHideHistory_clicked(bool checked) { if(checked) { ui->btnHideHistory->setText("显示历史"); ui->groupBoxRecord->hide(); //隐藏 } else { ui->btnHideHistory->setText("隐藏历史"); ui->groupBoxRecord->show(); //展示 } } //刷新串口号 void Widget::refreshSerialName() { ui->comboBox_serialnum->clear(); //清空comboBox QList serialList= QSerialPortInfo::availablePorts(); //获取系统中可用的串口 for(QSerialPortInfo serialInfo : serialList) //遍历所有可用串口 { qDebug() << serialInfo.portName(); ui->comboBox_serialnum->addItem(serialInfo.portName()); //将serialInfo对象所代表的串口添加到UI中 } ui->labelSendStatus->setText("Com Refresh"); } //指令发送,1,2,3 void Widget::on_command_button_clicked() { QPushButton *btn = qobject_cast(sender()); if(btn) { int num = btn->property("buttonId").toInt(); QString lineEditName = QString("lineEdit_%1").arg(num); QLineEdit *lineEdit = findChild(lineEditName); if(lineEdit) { ui->lineEditSendContex->setText(lineEdit->text()); } QString checkBoxName = QString("checkBox_%1").arg(num); QCheckBox * checkBox = findChild(checkBoxName); if(checkBox) ui->checkBHexSend->setChecked(checkBox->isChecked()); on_btnSendContex_clicked(); //发送文本 } } void Widget::buttons_handler() { if(buttonIndex < buttons.size()) { QPushButton* btnTmp = buttons[buttonIndex]; emit btnTmp->clicked(); buttonIndex++; } else { buttonIndex = 0; } } void Widget::on_checkBox_send_clicked(bool checked) { if(checked) { ui->spinBox->setEnabled(false); mythread->start(); // buttonConTimer->start(ui->spinBox->text().toUInt()); } else { ui->spinBox->setEnabled(true); mythread->terminate(); //立即终止进程 buttonConTimer->stop(); } } //重置 void Widget::on_btnInit_clicked() { // 创建一个消息框对象 QMessageBox msgBox; msgBox.setWindowTitle("提示"); // 设置消息框标题 msgBox.setIcon(QMessageBox::Question); // 设置消息框图标为问号,表示询问 msgBox.setText("重置列表不可逆,确认是否重置?"); // 设置消息框显示的文本 QPushButton *yesButton = msgBox.addButton("是",QMessageBox::YesRole); //添加自定义按钮是 QPushButton *noButton = msgBox.addButton("否",QMessageBox::NoRole); //添加自定义按钮否 msgBox.exec(); // 显示消息框,并等待用户响应 // 检查用户点击了哪个按钮 if(msgBox.clickedButton() == yesButton) { qDebug() << "yesButton"; //遍历lineEdit,并清空内容 for(int i = 0; i < lineEdits.size(); i++) { lineEdits[i]->clear(); //遍历checkBox,并取消勾选 checkBoxs[i]->setChecked(false); } } if(msgBox.clickedButton() == noButton) //如果用户点击了否 { qDebug() << "noButton"; } } ``` #### 串口调试助手保存,载入 Widget.h ``` #ifndef WIDGET_H #define WIDGET_H #include #include #include #include #include "mycombobox.h" #include "customthread.h" QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private slots: void on_btncloseorOpen_clicked(bool checked); //打开或关闭串口 void on_btnSendContex_clicked(); //发送数据 void on_SerialData_readyToRead(); //准备去读数据 void on_checkBoxSendInTime_clicked(bool checked); //定时发送 void on_btnrevClear_clicked(); //接收清楚 void on_btnrevSave_clicked(); //保存接收 void time_reflash(); //更新系统时间 void on_checkBoxHexDisplay_clicked(bool checked); //Hex显示 void on_btnhideTable_clicked(bool checked); //隐藏面板 void on_btnHideHistory_clicked(bool checked); //隐藏历史 void refreshSerialName(); //刷新串口名字 void on_command_button_clicked(); //序号被点击 void on_checkBox_send_clicked(bool checked); void buttons_handler(); void on_btnReset_clicked(); //重置 void on_btnSave_clicked(); //保存 void on_btnLoad_clicked(); //载入 private: QSerialPort *serialPort; //声明一个对象,串口 int writeCntTotal; //统计发送了多少字节 int readCntTotal; //统计发送了多少字节 QString SendBack; //返回上一次输入的数据 QString MyTime; //系统时间 bool serialStatus; //确认状态 QTimer *timer; //定时发送 void getSysTime(); //获取系统时间 QTimer *buttonConTimer; // int buttonIndex; CustomThread *mythread; QList buttons; QList lineEdits; QList checkBoxs; Ui::Widget *ui; }; #endif // WIDGET_H ``` Widget.cpp ``` #include "widget.h" #include "ui_widget.h" #include #include #include #include #include #include #include Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); this->setLayout(ui->gridLayoutGlobal); //让界面随着窗口变幻大小 ui->btnSendContex->setEnabled(false); //刚打开串口,发送按钮是失效的 ui->checkBoxSendInTime->setEnabled(false); //刚打开串口界面,定时发送选择框是失效的 ui->checkBoxrevTime->setEnabled(false); //刚打开串口界面,接收时间选择框是失效的 serialPort = new QSerialPort(this); //创建一个QSerialPort对象,将指针赋值给serialPort变量 QTimer *getSysTimeTimer = new QTimer(this); //创建一个QTimer对象,将指针赋值给getSysTimeTimer connect(getSysTimeTimer,SIGNAL(timeout()),this,SLOT(time_reflash())); getSysTimeTimer->start(100); //启动定时器,每隔100毫秒触发一次timeout信号 timer = new QTimer(this); //创建一个时间对象 // buttonConTimer = new QTimer(this); //定时器 // connect(buttonConTimer,&QTimer::timeout,this, &Widget::buttons_handler); mythread = new CustomThread(this); //线程 connect(mythread,&CustomThread::threadTimeout,this,&Widget::buttons_handler); //控制参数初始化 buttonIndex = 0; writeCntTotal = 0; //写入字节数 readCntTotal = 0; //读取字节数 serialStatus = false; //失效状态 //控件初始化 ui->btnSendContex->setEnabled(false); //发送按钮失效 ui->checkBoxSendInTime->setEnabled(false); //定时发送按钮失效 ui->checkSendNewLine->setEnabled(false); //发送新行失效 ui->checkBHexSend->setEnabled(false); //HEX发送失效 connect(timer,&QTimer::timeout,this,[=](){ on_btnSendContex_clicked(); }); //连接信号与槽,到点就发送文本 connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_SerialData_readyToRead); //连接函数,当接收数据可读时 connect(ui->comboBox_serialnum,&MyComboBox::refresh,this,&Widget::refreshSerialName); ui->comboBox_boautrate->setCurrentIndex(6); //将波特率索引值设置为6,方便选择 ui->comboBox_databit->setCurrentIndex(3); //将数据位索引值设置为3,方便选择 refreshSerialName(); ui->labelSendStatus->setText(ui->comboBox_serialnum->itemText(0)+" " + "NoOpen"); //状态文本初始化 for(int i = 1; i<=9; i++) { QString btnName = QString("pushButton_%1").arg(i); //从1到9 QPushButton* btn = findChild (btnName); if(btn) { btn->setProperty("buttonId",i); buttons.append(btn); connect(btn,SIGNAL(clicked()),this,SLOT(on_command_button_clicked())); } QString lineEditName = QString("lineEdit_%1").arg(i); QLineEdit *lineEdit = findChild(lineEditName); lineEdits.append(lineEdit); QString checkBoxName = QString("checkBox_%1").arg(i); QCheckBox *checkBox = findChild(checkBoxName); checkBoxs.append(checkBox); } } Widget::~Widget() { delete ui; } //打开或关闭串口 void Widget::on_btncloseorOpen_clicked(bool checked) { if(checked) { //1.选择端口号 serialPort->setPortName(ui->comboBox_serialnum->currentText()); //获取串口,把串口显示到文本上 //2.配置波特率 serialPort->setBaudRate(ui->comboBox_boautrate->currentText().toInt()); //显示波特率,转整型 //3.配置数据位 serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_databit->currentText().toInt())); //显示波特率,转整型 //4.配置校验位 switch (ui->comboBox_jiaoyan->currentText().toInt()) //用户选择校验位,并转为整型 { 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; } //5.配置停止位 serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_stopbit->currentText().toInt())); //显示停止位,转整型 //6.流控 if(ui->comboBox_fluidCon->currentText() == "None") //用户选择了None { serialPort->setFlowControl(QSerialPort::NoFlowControl); //执行,无流控 } //7.打开串口 if(serialPort->open(QIODevice::ReadWrite)) { qDebug() << "serial open success"; ui->comboBox_databit->setEnabled(false); //成功打开串口,这些按钮就失效 ui->comboBox_fluidCon->setEnabled(false); ui->comboBox_jiaoyan->setEnabled(false); ui->comboBox_stopbit->setEnabled(false); ui->comboBox_boautrate->setEnabled(false); ui->comboBox_serialnum->setEnabled(false); ui->btncloseorOpen->setText("关闭串口"); ui->btnSendContex->setEnabled(true); ui->checkBoxSendInTime->setEnabled(true); //成功打开串口,定时发送按钮生效 ui->checkSendNewLine->setEnabled(true); //发送新行生效 ui->checkBHexSend->setEnabled(true); //HEX发送生效 ui->labelSendStatus->setText(ui->comboBox_serialnum->currentText() + " " + "isOpen"); } else { qDebug() << "error"; QMessageBox msgBox; //弹窗 msgBox.setWindowTitle("打开串口错误"); msgBox.setText("打开失败,串口可能被占用或已拔出"); msgBox.exec(); } } else { serialPort->close(); ui->btncloseorOpen->setText("打开串口"); ui->comboBox_databit->setEnabled(true); //没有打开串口,这些按钮都是生效的 ui->comboBox_fluidCon->setEnabled(true); ui->comboBox_jiaoyan->setEnabled(true); ui->comboBox_stopbit->setEnabled(true); ui->comboBox_boautrate->setEnabled(true); ui->comboBox_serialnum->setEnabled(true); //serialStatus = false; ui->btnSendContex->setEnabled(false); //没有打开串口,发送按钮失效 ui->checkBoxSendInTime->setEnabled(false); //打开串口失败,定时发送按钮失效 ui->checkBoxSendInTime->setCheckState(Qt::Unchecked); //设置复选框为未选中状态 //关闭定时器 timer->stop(); ui->lineEditTimeeach->setEnabled(true); ui->lineEditSendContex->setEnabled(true); ui->checkSendNewLine->setEnabled(false); //发送新行失效 ui->checkBHexSend->setEnabled(false); //HEX发送失效 ui->labelSendStatus->setText(ui->comboBox_serialnum->currentText() + " " + "isClose"); } } //发送数据 void Widget::on_btnSendContex_clicked() { int writeCnt = 0; const char* sendData = ui->lineEditSendContex->text().toLocal8Bit().constData(); //把发送文本转换为C字符串指针 if(ui->checkBHexSend->isChecked()) //判断按键是否被按下 { QString tmp = ui->lineEditSendContex->text().toLocal8Bit().constData(); //判断是否是偶数位,16进制是两位 QByteArray tmpArray = tmp.toLocal8Bit(); if(tmpArray.size() % 2 != 0) { ui->labelSendStatus->setText("Error Input"); } //判断是否符合16进制的表达 for(char c : tmpArray) //定义一个c,遍历tmpArray数组 { if(!std::isxdigit(c)) //判断每一位是不是十六进制 { ui->labelSendStatus->setText("Error Input"); return; } } //转换成16进制发送,用户输入1,变成1,不会变成字符1,ASCII码 QByteArray arraySend = QByteArray::fromHex(tmpArray); //发送16进制 writeCnt = serialPort->write(arraySend); } else { //如果不是16进制发送 if(ui->checkSendNewLine->isChecked()) { QByteArray arraySendData(sendData,strlen(sendData)); arraySendData.append("\r\n"); writeCnt = serialPort->write(arraySendData); //返回实际写入的字节数 } else { writeCnt = serialPort->write(sendData); //返回实际写入的字节数 } } //发送失败清空 if(writeCnt == -1) { ui->labelSendStatus->setText("Send Error!"); //返回字节数失败,表示发送错误 } else { writeCntTotal += writeCnt; //写入成功,将字节数累加到writeCntTotal变量上 qDebug() << "SendOK" << sendData; //输出SendOK和sendData里面的内容 ui->labelSendStatus->setText("Send OK!"); //把发送状态改为Send OK ui->labelSendcnt->setNum(writeCntTotal); if(strcmp(sendData,SendBack.toStdString().c_str()) != 0) //比较sendData和上一次输出的数据是否相同 { ui->textEditRecord->append(sendData); //不同则在textEditRecord里追加数据 SendBack = QString::fromUtf8(sendData); //将数据转成QString类型,以便下次使用 } } } //读取发送的数据 void Widget::on_SerialData_readyToRead() { QString revMessage = serialPort->readAll(); //读取数据存于revMessage // qDebug() << "revCnt" << revMessage.size() << "context:" << revMessage; if(revMessage != NULL) //检查指针 revMessage 是否为非空指针,读取数据不为空 { if(ui->checkBLine->isChecked()) { revMessage.append("\r\n"); } //16进制显示 if(ui->checkBoxHexDisplay->isChecked()) //判断Hex显示是否被勾选 { QByteArray tmpHexString = revMessage.toUtf8().toHex().toUpper(); //原来控件上的内容,hex QString tmpStringHex = ui->textEditRev->toPlainText(); //因为勾选了,读出来就是Hex tmpHexString = tmpStringHex.toUtf8() + tmpHexString; //把读出的就的hex和新收到的数据转成hex进行拼接 ui->textEditRev->setText(QString::fromUtf8(tmpHexString)); //重新显示在控件上 } //非十六进制显示 else { if(ui->checkBoxrevTime->isChecked()) { getSysTime(); QString message = ui->lineEditSendContex->text() + " " + "【"+MyTime+"】"; ui->textEditRev->insertPlainText(message); } else { ui->textEditRev->insertPlainText(revMessage); //将收到的内容追加到textEditRev文本框中 } } } readCntTotal += revMessage.size(); //接收的总字节数 ui->labelRevcnt->setNum(readCntTotal); //计算接收到的字节数 } //自动发送 void Widget::on_checkBoxSendInTime_clicked(bool checked) { // qDebug() <<"checkBsendIntime" << checked; if(checked) //检测复选框是否被选中 { ui->lineEditTimeeach->setEnabled(false); //定时发送开始,定时文本无效 ui->lineEditTimeeach->setEnabled(false); //定时发送开始,发送文本无效 timer->start(1000); //启动定时器 timer->start(ui->lineEditTimeeach->text().toInt()); //允许用户修改时间间隔 //on_btnSendContex_clicked(); } else { timer->stop(); //停止定时器 ui->lineEditTimeeach->setEnabled(true); //定时器停止后,定时文本变有效 ui->lineEditSendContex->setEnabled(true); //定时器停止后,发送文本变有效 } } //清空接收 void Widget::on_btnrevClear_clicked() { ui->textEditRev->setText(""); //清空接收内容 } //保存接收内容 void Widget::on_btnrevSave_clicked() { QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "L:/QTproject/QT/serialData.txt", tr("Text (*.txt)")); //弹出文件选择框,保存文件 if(fileName != NULL) { QFile file(fileName); //创建一个 QFile 对象,用于操作文件 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return; //打开文件失败,则直接返回 } QTextStream out(&file); //创建一个QTextStream 对象,用于将数据写入文件 out <textEditRev->toPlainText(); //获取文本内容,输出到流out file.close(); //关闭文件 } } //更新串口调试助手时间 void Widget::time_reflash() { getSysTime(); ui->labelCurrentTime->setText(MyTime); } //获取系统时间 void Widget::getSysTime() { QDateTime currentTime = QDateTime::currentDateTime(); //创建一个currentTime对象,返回当前系统时间 QDate date = currentTime.date(); //返回一个日期对象date int year = date.year(); //获取年份,存储在year变量中 int month = date.month(); //获取月份,存储在month变量中 int day = date.day(); //获取日,存储在day变量中 QTime time = currentTime.time(); //创建一个time对象,返回时间 int hour = time.hour(); //获取时,存储在hour变量中 int minute = time.minute(); //获取时,存储在minute变量中 int second = time.second(); //获取时,存储在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')); } //Hex显示 void Widget::on_checkBoxHexDisplay_clicked(bool checked) { if(checked) //如果打勾 { //1.读取textEdit内容 QString tmp = ui->textEditRev->toPlainText(); //2.转换成hex(因为QByteArray有toHex(),所以转换成QByteArray) QByteArray qtmp = tmp.toUtf8(); //因为QSrting没有把小写字母a转化成61的能力,QByteArray有,所以用QByteArray qtmp = qtmp.toHex(); //3.显示 QString lastShow; tmp = QString::fromUtf8(qtmp); //把QByteArray转换成QString格式 for(int i = 0; itextEditRev->setText(lastShow.toUpper()); //转换成大写 } else { //1.读取textEdit内容,hex QString tmpHexString = ui->textEditRev->toPlainText(); //2.将 QString 转换为 QByteArray QByteArray tmpHexQBytearray = tmpHexString.toUtf8(); //3.将十六进制字符串转换为字节数组 QByteArray tmpQByteString = QByteArray::fromHex(tmpHexQBytearray); //将61转换成a //4.显示 ui->textEditRev->setText(QString::fromUtf8(tmpQByteString)); } } void Widget::on_btnhideTable_clicked(bool checked) { if(checked) { ui->btnhideTable->setText("拓展面板"); ui->groupBoxTexts->hide(); //隐藏 } else { ui->btnhideTable->setText("隐藏面板"); ui->groupBoxTexts->show(); //展示 } } void Widget::on_btnHideHistory_clicked(bool checked) { if(checked) { ui->btnHideHistory->setText("显示历史"); ui->groupBoxRecord->hide(); //隐藏 } else { ui->btnHideHistory->setText("隐藏历史"); ui->groupBoxRecord->show(); //展示 } } //刷新串口号 void Widget::refreshSerialName() { ui->comboBox_serialnum->clear(); //清空comboBox QList serialList= QSerialPortInfo::availablePorts(); //获取系统中可用的串口 for(QSerialPortInfo serialInfo : serialList) //遍历所有可用串口 { qDebug() << serialInfo.portName(); ui->comboBox_serialnum->addItem(serialInfo.portName()); //将serialInfo对象所代表的串口添加到UI中 } ui->labelSendStatus->setText("Com Refresh"); } //指令发送,1,2,3 void Widget::on_command_button_clicked() { QPushButton *btn = qobject_cast(sender()); if(btn) { int num = btn->property("buttonId").toInt(); QString lineEditName = QString("lineEdit_%1").arg(num); QLineEdit *lineEdit = findChild(lineEditName); if(lineEdit) { ui->lineEditSendContex->setText(lineEdit->text()); } QString checkBoxName = QString("checkBox_%1").arg(num); QCheckBox * checkBox = findChild(checkBoxName); if(checkBox) ui->checkBHexSend->setChecked(checkBox->isChecked()); on_btnSendContex_clicked(); //发送文本 } } void Widget::buttons_handler() { if(buttonIndex < buttons.size()) { QPushButton* btnTmp = buttons[buttonIndex]; emit btnTmp->clicked(); buttonIndex++; } else { buttonIndex = 0; } } void Widget::on_checkBox_send_clicked(bool checked) { if(checked) { ui->spinBox->setEnabled(false); mythread->start(); // buttonConTimer->start(ui->spinBox->text().toUInt()); } else { ui->spinBox->setEnabled(true); mythread->terminate(); //立即终止进程 buttonConTimer->stop(); } } //重置 void Widget::on_btnReset_clicked() { QMessageBox msgBox; msgBox.setWindowTitle("提示"); msgBox.setIcon(QMessageBox::Question); msgBox.setText("重置列表不可逆,确认是否重置?"); // msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); QPushButton *yesButton = msgBox.addButton("是",QMessageBox::YesRole); QPushButton *noButton = msgBox.addButton("否",QMessageBox::NoRole); msgBox.exec(); if(msgBox.clickedButton() == yesButton) { qDebug() << "yesButton"; //遍历lineEdit,并清空内容 for(int i = 0; i < lineEdits.size(); i++) { lineEdits[i]->clear(); //遍历checkBox,并取消勾选 checkBoxs[i]->setChecked(false); } } if(msgBox.clickedButton() == noButton) { qDebug() << "noButton"; } } //保存 void Widget::on_btnSave_clicked() { // 打开文件保存对话框,让用户选择或输入要保存的文件名。 QString fileName = QFileDialog::getSaveFileName(this, tr("保存文件"), "L:/QTproject/QT", tr("文件类型(*.txt)")); QFile file(fileName); // 使用用户选定的文件名创建一个QFile对象 //以写入模式打开文件 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) return; // 创建一个QTextStream对象out,用于将数据写入到文件中 QTextStream out(&file); // 遍历所有存储在lineEdits容器中的LineEdit控件 for(int i = 0; i< lineEdits.size();i++) { out << checkBoxs[i]->isChecked() << "," << lineEdits[i]->text() << "\n"; } file.close(); // 关闭文件,确保所有数据都被正确写入并释放资源 } //载入 void Widget::on_btnLoad_clicked() { int i = 0; // 初始化一个计数器i,用于跟踪处理的行数 // 打开文件打开对话框,让用户选择要加载的文件 QString fileName = QFileDialog::getOpenFileName(this, tr("打开文件"), "L:/QTproject/QT", tr("文件类型(*.txt)")); //检查是否成功选择了文件 if(!fileName.isEmpty()) { QFile file(fileName); // 使用用户选定的文件名创建一个QFile对象 if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) //以只读模式打开 return; // 创建一个QTextStream对象in,用于从文件中读取数据 QTextStream in(&file); // 循环读取文件中的每一行,直到文件结束或处理了9行数据 while(!in.atEnd() && i<9) { QString line = in.readLine(); // 读取一行文本 QStringList parts = line.split(","); // 将该行文本按“,”分割成多个部分 // 检查分割后的部分数量是否为2 if(parts.count() == 2) { checkBoxs[i]->setChecked(parts[0].toInt()); // 设置第i个CheckBox控件的状态 lineEdits[i]->setText(parts[1]); // 设置第i个LineEdit控件的文本内容 } i++; // 增加计数器,准备处理下一行数据 } } } ``` #### 串口调试助手总结 Widget.h ``` #ifndef WIDGET_H #define WIDGET_H #include #include #include #include #include "mycombobox.h" #include "customthread.h" QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private slots: void on_btncloseorOpen_clicked(bool checked); //打开或关闭串口 void on_btnSendContex_clicked(); //发送数据 void on_SerialData_readyToRead(); //准备去读数据 void on_checkBoxSendInTime_clicked(bool checked); //定时发送 void on_btnrevClear_clicked(); //接收清楚 void on_btnrevSave_clicked(); //保存接收 void time_reflash(); //更新系统时间 void on_checkBoxHexDisplay_clicked(bool checked); //Hex显示 void on_btnhideTable_clicked(bool checked); //隐藏面板 void on_btnHideHistory_clicked(bool checked); //隐藏历史 void refreshSerialName(); //刷新串口名字 void on_command_button_clicked(); //序号被点击 void on_checkBox_send_clicked(bool checked); void buttons_handler(); void on_btnReset_clicked(); //重置 void on_btnSave_clicked(); //保存 void on_btnLoad_clicked(); //载入 private: QSerialPort *serialPort; //声明一个对象,串口 int writeCntTotal; //统计发送了多少字节 int readCntTotal; //统计发送了多少字节 QString SendBack; //返回上一次输入的数据 QString MyTime; //系统时间 bool serialStatus; //确认状态 QTimer *timer; //定时发送 void getSysTime(); //获取系统时间 QTimer *buttonConTimer; // int buttonIndex; CustomThread *mythread; QList buttons; QList lineEdits; QList checkBoxs; Ui::Widget *ui; }; #endif // WIDGET_H ``` Widget.cpp ``` #include "widget.h" #include "ui_widget.h" #include #include #include #include #include #include #include Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); this->setLayout(ui->gridLayoutGlobal); //让界面随着窗口变幻大小 ui->btnSendContex->setEnabled(false); //刚打开串口,发送按钮是失效的 ui->checkBoxSendInTime->setEnabled(false); //刚打开串口界面,定时发送选择框是失效的 ui->checkBoxrevTime->setEnabled(false); //刚打开串口界面,接收时间选择框是失效的 ui->btnSave->setEnabled(false); //刚打开串口界面,接收时间选择框是失效的 ui->btnLoad->setEnabled(false); //刚打开串口界面,接收时间选择框是失效的 ui->btnReset->setEnabled(false); //刚打开串口界面,接收时间选择框是失效的 serialPort = new QSerialPort(this); //创建一个QSerialPort对象,将指针赋值给serialPort变量 QTimer *getSysTimeTimer = new QTimer(this); //创建一个QTimer对象,将指针赋值给getSysTimeTimer connect(getSysTimeTimer,SIGNAL(timeout()),this,SLOT(time_reflash())); getSysTimeTimer->start(100); //启动定时器,每隔100毫秒触发一次timeout信号 timer = new QTimer(this); //创建一个时间对象 // buttonConTimer = new QTimer(this); //定时器 // connect(buttonConTimer,&QTimer::timeout,this, &Widget::buttons_handler); mythread = new CustomThread(this); //线程 connect(mythread,&CustomThread::threadTimeout,this,&Widget::buttons_handler); //控制参数初始化 buttonIndex = 0; writeCntTotal = 0; //写入字节数 readCntTotal = 0; //读取字节数 serialStatus = false; //失效状态 //控件初始化 ui->btnSendContex->setEnabled(false); //发送按钮失效 ui->checkBoxSendInTime->setEnabled(false); //定时发送按钮失效 ui->checkSendNewLine->setEnabled(false); //发送新行失效 ui->checkBHexSend->setEnabled(false); //HEX发送失效 connect(timer,&QTimer::timeout,this,[=](){ on_btnSendContex_clicked(); }); //连接信号与槽,到点就发送文本 connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_SerialData_readyToRead); //连接函数,当接收数据可读时 connect(ui->comboBox_serialnum,&MyComboBox::refresh,this,&Widget::refreshSerialName); ui->comboBox_boautrate->setCurrentIndex(6); //将波特率索引值设置为6,方便选择 ui->comboBox_databit->setCurrentIndex(3); //将数据位索引值设置为3,方便选择 refreshSerialName(); ui->labelSendStatus->setText(ui->comboBox_serialnum->itemText(0)+" " + "NoOpen"); //状态文本初始化 for(int i = 1; i<=9; i++) { QString btnName = QString("pushButton_%1").arg(i); //从1到9 QPushButton* btn = findChild (btnName); if(btn) { btn->setProperty("buttonId",i); buttons.append(btn); connect(btn,SIGNAL(clicked()),this,SLOT(on_command_button_clicked())); } QString lineEditName = QString("lineEdit_%1").arg(i); QLineEdit *lineEdit = findChild(lineEditName); lineEdits.append(lineEdit); QString checkBoxName = QString("checkBox_%1").arg(i); QCheckBox *checkBox = findChild(checkBoxName); checkBoxs.append(checkBox); } } Widget::~Widget() { delete ui; } //打开或关闭串口 void Widget::on_btncloseorOpen_clicked(bool checked) { if(checked) { //1.选择端口号 serialPort->setPortName(ui->comboBox_serialnum->currentText()); //获取串口,把串口显示到文本上 //2.配置波特率 serialPort->setBaudRate(ui->comboBox_boautrate->currentText().toInt()); //显示波特率,转整型 //3.配置数据位 serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_databit->currentText().toInt())); //显示波特率,转整型 //4.配置校验位 switch (ui->comboBox_jiaoyan->currentText().toInt()) //用户选择校验位,并转为整型 { 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; } //5.配置停止位 serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_stopbit->currentText().toInt())); //显示停止位,转整型 //6.流控 if(ui->comboBox_fluidCon->currentText() == "None") //用户选择了None { serialPort->setFlowControl(QSerialPort::NoFlowControl); //执行,无流控 } //7.打开串口 if(serialPort->open(QIODevice::ReadWrite)) { // qDebug() << "serial open success"; ui->comboBox_databit->setEnabled(false); //成功打开串口,这些按钮就失效 ui->comboBox_fluidCon->setEnabled(false); ui->comboBox_jiaoyan->setEnabled(false); ui->comboBox_stopbit->setEnabled(false); ui->comboBox_boautrate->setEnabled(false); ui->comboBox_serialnum->setEnabled(false); ui->btncloseorOpen->setText("关闭串口"); ui->btnSendContex->setEnabled(true); ui->checkBoxSendInTime->setEnabled(true); //成功打开串口,定时发送按钮生效 ui->checkSendNewLine->setEnabled(true); //发送新行生效 ui->checkBHexSend->setEnabled(true); //HEX发送生效 ui->btnSave->setEnabled(true); ui->btnLoad->setEnabled(true); ui->btnReset->setEnabled(true); ui->checkBoxrevTime->setEnabled(true); //刚打开串口界面,接收时间选择框是失效的 ui->labelSendStatus->setText(ui->comboBox_serialnum->currentText() + " " + "isOpen"); } else { // qDebug() << "error"; QMessageBox msgBox; //弹窗 msgBox.setWindowTitle("打开串口错误"); msgBox.setText("打开失败,串口可能被占用或已拔出"); msgBox.exec(); } } else { serialPort->close(); ui->btncloseorOpen->setText("打开串口"); ui->comboBox_databit->setEnabled(true); //没有打开串口,这些按钮都是生效的 ui->comboBox_fluidCon->setEnabled(true); ui->comboBox_jiaoyan->setEnabled(true); ui->comboBox_stopbit->setEnabled(true); ui->comboBox_boautrate->setEnabled(true); ui->comboBox_serialnum->setEnabled(true); //serialStatus = false; ui->btnSendContex->setEnabled(false); //没有打开串口,发送按钮失效 ui->checkBoxSendInTime->setEnabled(false); //打开串口失败,定时发送按钮失效 ui->checkBoxSendInTime->setCheckState(Qt::Unchecked); //设置复选框为未选中状态 //关闭定时器 timer->stop(); ui->lineEditTimeeach->setEnabled(true); ui->lineEditSendContex->setEnabled(true); ui->checkSendNewLine->setEnabled(false); //发送新行失效 ui->checkBHexSend->setEnabled(false); //HEX发送失效 ui->btnSave->setEnabled(false); ui->btnLoad->setEnabled(false); ui->btnReset->setEnabled(false); ui->checkBoxrevTime->setEnabled(false); //刚打开串口界面,接收时间选择框是失效的 ui->labelSendStatus->setText(ui->comboBox_serialnum->currentText() + " " + "isClose"); } } //发送数据 void Widget::on_btnSendContex_clicked() { int writeCnt = 0; const char* sendData = ui->lineEditSendContex->text().toLocal8Bit().constData(); //把发送文本转换为C字符串指针 if(ui->checkBHexSend->isChecked()) //判断按键是否被按下 { QString tmp = ui->lineEditSendContex->text().toLocal8Bit().constData(); //判断是否是偶数位,16进制是两位 QByteArray tmpArray = tmp.toLocal8Bit(); if(tmpArray.size() % 2 != 0) { ui->labelSendStatus->setText("Error Input"); } //判断是否符合16进制的表达 for(char c : tmpArray) //定义一个c,遍历tmpArray数组 { if(!std::isxdigit(c)) //判断每一位是不是十六进制 { ui->labelSendStatus->setText("Error Input"); return; } } //转换成16进制发送,用户输入1,变成1,不会变成字符1,ASCII码 QByteArray arraySend = QByteArray::fromHex(tmpArray); //发送16进制 writeCnt = serialPort->write(arraySend); } else { //如果不是16进制发送 if(ui->checkSendNewLine->isChecked()) { QByteArray arraySendData(sendData,strlen(sendData)); arraySendData.append("\r\n"); writeCnt = serialPort->write(arraySendData); //返回实际写入的字节数 } else { writeCnt = serialPort->write(sendData); //返回实际写入的字节数 } } //发送失败清空 if(writeCnt == -1) { ui->labelSendStatus->setText("Send Error!"); //返回字节数失败,表示发送错误 } else { writeCntTotal += writeCnt; //写入成功,将字节数累加到writeCntTotal变量上 // qDebug() << "SendOK" << sendData; //输出SendOK和sendData里面的内容 ui->labelSendStatus->setText("Send OK!"); //把发送状态改为Send OK ui->labelSendcnt->setNum(writeCntTotal); if(strcmp(sendData,SendBack.toStdString().c_str()) != 0) //比较sendData和上一次输出的数据是否相同 { ui->textEditRecord->append(sendData); //不同则在textEditRecord里追加数据 SendBack = QString::fromUtf8(sendData); //将数据转成QString类型,以便下次使用 } } } //读取发送的数据 void Widget::on_SerialData_readyToRead() { QString revMessage = serialPort->readAll(); //读取数据存于revMessage // qDebug() << "revCnt" << revMessage.size() << "context:" << revMessage; if(revMessage != NULL) //检查指针 revMessage 是否为非空指针,读取数据不为空 { if(ui->checkBLine->isChecked()) { revMessage.append("\r\n"); } //16进制显示 if(ui->checkBoxHexDisplay->isChecked()) //判断Hex显示是否被勾选 { QByteArray tmpHexString = revMessage.toUtf8().toHex().toUpper(); //原来控件上的内容,hex QString tmpStringHex = ui->textEditRev->toPlainText(); //因为勾选了,读出来就是Hex tmpHexString = tmpStringHex.toUtf8() + tmpHexString; //把读出的就的hex和新收到的数据转成hex进行拼接 ui->textEditRev->setText(QString::fromUtf8(tmpHexString)); //重新显示在控件上 } //非十六进制显示 else { if(ui->checkBoxrevTime->isChecked()) { getSysTime(); QString message = revMessage + "【"+MyTime+"】"; ui->textEditRev->insertPlainText(message); // 确保光标移动到末尾 QTextCursor cursor = ui->textEditRev->textCursor(); cursor.movePosition(QTextCursor::End); ui->textEditRev->setTextCursor(cursor); } else { ui->textEditRev->insertPlainText(revMessage); //将收到的内容追加到textEditRev文本框中 // 确保光标移动到末尾 QTextCursor cursor = ui->textEditRev->textCursor(); cursor.movePosition(QTextCursor::End); ui->textEditRev->setTextCursor(cursor); } } } readCntTotal += revMessage.size(); //接收的总字节数 ui->labelRevcnt->setNum(readCntTotal); //计算接收到的字节数 //光标跟随接收界面移动 ui->textEditRev->moveCursor(QTextCursor::End); ui->textEditRev->ensureCursorVisible(); } //自动发送 void Widget::on_checkBoxSendInTime_clicked(bool checked) { // qDebug() <<"checkBsendIntime" << checked; if(checked) //检测复选框是否被选中 { ui->lineEditTimeeach->setEnabled(false); //定时发送开始,定时文本无效 ui->lineEditTimeeach->setEnabled(false); //定时发送开始,发送文本无效 timer->start(1000); //启动定时器 timer->start(ui->lineEditTimeeach->text().toInt()); //允许用户修改时间间隔 //on_btnSendContex_clicked(); } else { timer->stop(); //停止定时器 ui->lineEditTimeeach->setEnabled(true); //定时器停止后,定时文本变有效 ui->lineEditSendContex->setEnabled(true); //定时器停止后,发送文本变有效 } } //清空接收 void Widget::on_btnrevClear_clicked() { ui->textEditRev->setText(""); //清空接收内容 } //保存接收内容 void Widget::on_btnrevSave_clicked() { QString fileName = QFileDialog::getSaveFileName(this, tr("保存文件"), "L:/QTproject/QT/serialData.txt", tr("文件类型(*.txt)")); //弹出文件选择框,保存文件 if(fileName != NULL) { QFile file(fileName); //创建一个 QFile 对象,用于操作文件 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return; //打开文件失败,则直接返回 } QTextStream out(&file); //创建一个QTextStream 对象,用于将数据写入文件 out <textEditRev->toPlainText(); //获取文本内容,输出到流out file.close(); //关闭文件 } } //更新串口调试助手时间 void Widget::time_reflash() { getSysTime(); ui->labelCurrentTime->setText(MyTime); } //获取系统时间 void Widget::getSysTime() { QDateTime currentTime = QDateTime::currentDateTime(); //创建一个currentTime对象,返回当前系统时间 QDate date = currentTime.date(); //返回一个日期对象date int year = date.year(); //获取年份,存储在year变量中 int month = date.month(); //获取月份,存储在month变量中 int day = date.day(); //获取日,存储在day变量中 QTime time = currentTime.time(); //创建一个time对象,返回时间 int hour = time.hour(); //获取时,存储在hour变量中 int minute = time.minute(); //获取时,存储在minute变量中 int second = time.second(); //获取时,存储在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')); } //Hex显示 void Widget::on_checkBoxHexDisplay_clicked(bool checked) { if(checked) //如果打勾 { //1.读取textEdit内容 QString tmp = ui->textEditRev->toPlainText(); //2.转换成hex(因为QByteArray有toHex(),所以转换成QByteArray) QByteArray qtmp = tmp.toUtf8(); //因为QSrting没有把小写字母a转化成61的能力,QByteArray有,所以用QByteArray qtmp = qtmp.toHex(); //3.显示 QString lastShow; tmp = QString::fromUtf8(qtmp); //把QByteArray转换成QString格式 for(int i = 0; itextEditRev->setText(lastShow.toUpper()); //转换成大写 } else { //1.读取textEdit内容,hex QString tmpHexString = ui->textEditRev->toPlainText(); //2.将 QString 转换为 QByteArray QByteArray tmpHexQBytearray = tmpHexString.toUtf8(); //3.将十六进制字符串转换为字节数组 QByteArray tmpQByteString = QByteArray::fromHex(tmpHexQBytearray); //将61转换成a //4.显示 ui->textEditRev->setText(QString::fromUtf8(tmpQByteString)); } //光标跟随接收界面移动 ui->textEditRev->moveCursor(QTextCursor::End); ui->textEditRev->ensureCursorVisible(); } void Widget::on_btnhideTable_clicked(bool checked) { if(checked) { ui->btnhideTable->setText("拓展面板"); ui->groupBoxTexts->hide(); //隐藏 } else { ui->btnhideTable->setText("隐藏面板"); ui->groupBoxTexts->show(); //展示 } } void Widget::on_btnHideHistory_clicked(bool checked) { if(checked) { ui->btnHideHistory->setText("显示历史"); ui->groupBoxRecord->hide(); //隐藏 } else { ui->btnHideHistory->setText("隐藏历史"); ui->groupBoxRecord->show(); //展示 } } //刷新串口号 void Widget::refreshSerialName() { ui->comboBox_serialnum->clear(); //清空comboBox QList serialList= QSerialPortInfo::availablePorts(); //获取系统中可用的串口 for(QSerialPortInfo serialInfo : serialList) //遍历所有可用串口 { // qDebug() << serialInfo.portName(); ui->comboBox_serialnum->addItem(serialInfo.portName()); //将serialInfo对象所代表的串口添加到UI中 } ui->labelSendStatus->setText("Com Refresh"); } //指令发送,1,2,3 void Widget::on_command_button_clicked() { QPushButton *btn = qobject_cast(sender()); if(btn) { int num = btn->property("buttonId").toInt(); QString lineEditName = QString("lineEdit_%1").arg(num); QLineEdit *lineEdit = findChild(lineEditName); if(lineEdit) { ui->lineEditSendContex->setText(lineEdit->text()); } QString checkBoxName = QString("checkBox_%1").arg(num); QCheckBox * checkBox = findChild(checkBoxName); if(checkBox) ui->checkBHexSend->setChecked(checkBox->isChecked()); on_btnSendContex_clicked(); //发送文本 } } void Widget::buttons_handler() { if(buttonIndex < buttons.size()) { QPushButton* btnTmp = buttons[buttonIndex]; emit btnTmp->clicked(); buttonIndex++; } else { buttonIndex = 0; } } void Widget::on_checkBox_send_clicked(bool checked) { if(checked) { ui->spinBox->setEnabled(false); mythread->start(); // buttonConTimer->start(ui->spinBox->text().toUInt()); } else { ui->spinBox->setEnabled(true); mythread->terminate(); //立即终止进程 buttonConTimer->stop(); } } void Widget::on_btnReset_clicked() { QMessageBox msgBox; msgBox.setWindowTitle("提示"); msgBox.setIcon(QMessageBox::Question); msgBox.setText("重置列表不可逆,确认是否重置?"); // msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); QPushButton *yesButton = msgBox.addButton("是",QMessageBox::YesRole); QPushButton *noButton = msgBox.addButton("否",QMessageBox::NoRole); msgBox.exec(); if(msgBox.clickedButton() == yesButton) { // qDebug() << "yesButton"; //遍历lineEdit,并清空内容 for(int i = 0; i < lineEdits.size(); i++) { lineEdits[i]->clear(); //遍历checkBox,并取消勾选 checkBoxs[i]->setChecked(false); } } if(msgBox.clickedButton() == noButton) { // qDebug() << "noButton"; } } void Widget::on_btnSave_clicked() { // 打开一个文件保存对话框,让用户选择或输入要保存的文件名。 // 参数解释: // 1. this - 指向当前窗口部件的指针,作为对话框的父窗口。 // 2. tr("保存文件") - 对话框标题,使用tr()函数进行国际化支持。 // 3. "L:/QTproject/QT" - 默认打开的目录路径。 // 4. tr("文件类型(*.txt)") - 文件过滤器,限制用户只能看到和选择.txt类型的文件。 QString fileName = QFileDialog::getSaveFileName(this, tr("保存文件"), "L:/QTproject/QT", tr("文件类型(*.txt)")); // 使用用户选定的文件名创建一个QFile对象。 QFile file(fileName); // 尝试以写入模式打开文件。如果文件无法打开,则返回,不执行后续操作。 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) return; // 创建一个QTextStream对象out,用于将数据写入到文件中。 QTextStream out(&file); // 遍历所有存储在lineEdits容器中的LineEdit控件。 for (int i = 0; i < lineEdits.size(); i++) { // 写入第i个CheckBox控件的状态(是否被选中)以及对应的第i个LineEdit控件的内容。 // 数据格式为:checkBox状态(布尔值),lineEdit内容\n out << (checkBoxs[i]->isChecked() ? "1" : "0") << "," << lineEdits[i]->text() << "\n"; } // 关闭文件,确保所有数据都被正确写入并释放资源。 file.close(); } void Widget::on_btnLoad_clicked() { // 初始化一个计数器i,用于跟踪处理的行数。 int i = 0; // 打开一个文件打开对话框,让用户选择要加载的文件。 // 参数解释: // 1. this - 指向当前窗口部件的指针,作为对话框的父窗口。 // 2. tr("打开文件") - 对话框标题,使用tr()函数进行国际化支持。 // 3. "L:/QTproject/QT" - 默认打开的目录路径。 // 4. tr("文件类型(*.txt)") - 文件过滤器,限制用户只能看到和选择.txt类型的文件。 QString fileName = QFileDialog::getOpenFileName(this, tr("打开文件"), "L:/QTproject/QT", tr("文件类型(*.txt)")); // 检查是否成功选择了文件。如果fileName不为空,则继续执行。 if (!fileName.isEmpty()) // 更安全的检查方式,避免NULL指针问题 { // 使用用户选定的文件名创建一个QFile对象。 QFile file(fileName); // 尝试以只读模式打开文件。如果文件无法打开,则返回,不执行后续操作。 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) return; // 创建一个QTextStream对象in,用于从文件中读取数据。 QTextStream in(&file); // 循环读取文件中的每一行,直到文件结束或处理了9行数据。 while (!in.atEnd() && i < 9) { // 读取一行文本。 QString line = in.readLine(); // 将该行文本按逗号分割成多个部分。 QStringList parts = line.split(","); // 检查分割后的部分数量是否为2(即CheckBox状态和LineEdit内容)。 if (parts.count() == 2) { // 设置第i个CheckBox控件的状态(根据字符串转换为整数后的值)。 checkBoxs[i]->setChecked(parts[0].toInt()); // 设置第i个LineEdit控件的文本内容。 lineEdits[i]->setText(parts[1]); } // 增加计数器,准备处理下一行数据。 i++; } // 关闭文件,确保所有资源都被释放。 file.close(); } } ```