QT之串口调试助手

1. UI

• 如图:

2. 代码

2.1 在widget.cpp

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"

#include <QtSerialPort/QSerialPortInfo>
#include <QList>
#include <QSerialPort>
#include <QDebug>
#include <QMessageBox>
#include <QTimer>
#include <QFileDialog>
#include <QDateTime>
#include <QThread>



Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //拖拽窗口里面的控件也跟着发生变化
    this->setLayout(ui->gridLayoutGlobal);
    //自动检查电脑的串口
    refreshSerialName();
    //设置默认串口的属性
    //默认115200波特率,8位数据位,无校验位,无流控,1位停止位(后三个已经是默认的了)
    ui->comboBox_boautrate->setCurrentIndex(6);
    ui->comboBox_dataBit->setCurrentIndex(3);
    //设置刚刚打开的状态
    ui->labelSendStatus->setText(ui->comboBox_serialNum->currentText() + " NotOpen!");

    //默认设置控件不能操作,当没打开串口的时候,发送部分全不能操作(groupBoxDownRightLow这部分)。
    ui->btnSendContext->setEnabled(false);
    ui->lineEditSendContext->setEnabled(false);
    ui->checkBSendInTime->setEnabled(false);
    ui->checkBSendNewwLine->setEnabled(false);
    ui->checkBHexSend->setEnabled(false);
    ui->lineEditTimeEach->setEnabled(false);

    //打开串口助手
    //如果想要操作串口,打开串口,和串口通信,必须要包含这个类QSerialPort(重点)
    serialPort = new QSerialPort(this);//关联到本窗口

    //添加读取数据的信号与槽
    //readyRead() 信号是一个 "有新数据到达,可以读取了" 的通知。
    connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_SerialData_readyToRead);
    //初始化记录总共发了多少个字节writeCntTotal
    writeCntTotal = 0;
    //初始化记录总共j接收了多少个字节readCntTotal
    readCntTotal = 0;

    //定时发送需要定时器
    timer = new QTimer(this);//为当前窗口添加一个定时器
    //设置定时器,超时信号的信号与槽
    connect(timer,&QTimer::timeout,[=]{
        on_btnSendContext_clicked();//超时就把框内的内容发送出去
    });

    //创建一个定时器用来记录刷新右下角的时间
    QTimer *getSysTimeTimer = new QTimer(this);//为当前窗口添加一个定时器
    //建立信号与槽
    connect(getSysTimeTimer,SIGNAL(timeout()),this,SLOT(time_refresh()));
    //启动定时器
    getSysTimeTimer->start(100);

    //需要刷新串口列表,这需要信号与槽
    //需要每次点击comboBox_serialNum刷新,但是QComboBox是没有点击这个信号
    //所以需要重写鼠标点击事件
    connect(ui->comboBox_serialNum,SIGNAL(refresh()),this,SLOT(refreshSerialName()));

    //以数组的方式解决多文本的问题
    for(int i = 1;i <= 9;i++){
        //生成按钮名称:pushButton_1 到 pushButton_9
        QString btnName = QString("pushButton_%1").arg(i);
        //通过findChild在widget界面中寻找对应的子控件(类似使用"ui->"那样去找)
        QPushButton * btn = findChild<QPushButton *>(btnName);
        //判断是否找到了
        if(btn){
            //添加到数组里面
            buttons.append(btn);
            //如果找到了pushButton之后,为此按键创建对应的属性
            btn->setProperty("buttonId",i);
            //如果找到了,为对应的pushButton创建信号与槽
            //所有按钮连接到同一个槽函数
            //为每一个pushButton创建clicked的信号与槽
            connect(btn,SIGNAL(clicked()),this,SLOT(on_command_button_click()));
        }
        //继续保存lineEdits和checkBoxs

        //生成按钮名称:lineEdit_1 到 lineEdit_9
        QString lineEditName = QString("lineEdit_%1").arg(i);
        //通过findChild在widget界面中寻找对应的子控件(类似使用"ui->"那样去找)
        QLineEdit * lineEdit = findChild<QLineEdit *>(lineEditName);
        if(lineEdit)
            lineEdits.append(lineEdit);

        //生成按钮名称:checkBoxs_1 到 checkBoxs_9
        QString checkBoxName = QString("checkBox_%1").arg(i);
        //通过findChild在widget界面中寻找对应的子控件(类似使用"ui->"那样去找)
        QCheckBox * checkBox = findChild<QCheckBox *>(checkBoxName);
        if(checkBox)
            checkBoxs.append(checkBox);
    }

    //第一种方法是使用定时器解决
    //初始化循环发送的定时器
    buttonsConTimer = new QTimer(this);
    //建立信号与槽
    connect(buttonsConTimer,&QTimer::timeout,this,&Widget::buttons_handler);
    //初始化buttonIndex索引,这是用来表示buttons的索引,在循环发送中
    buttonIndex = 0;

    //第二种是使用线程方法,但是不是在UI里面使用线程
//    c1 = new customthread(this);
//    connect(c1,&customthread::threadTimeout,this,&Widget::buttons_handler);

}

void Widget::on_command_button_click(){
    //sender可以知道信号是那个pushButton发出的
    //qobject_cast的作用,可以安全的知道发出信号的是pushButton,不是其他的信号
    //获取触发信号的按钮对象
    QPushButton * btn = qobject_cast<QPushButton *>(sender());
    //判断是否找到
    if(btn){
        //qDebug() << btn->property("buttonId").toInt();
        //根据buttonId找到对应按键
        int num = btn->property("buttonId").toInt();
        //根据num找到对应的lineEdit
        QString lineEditName = QString("lineEdit_%1").arg(num);
        QLineEdit * lineEdit = findChild<QLineEdit *>(lineEditName);
        if(lineEdit){
            if(lineEdit->text().size() <= 0)
                return;
            ui->lineEditSendContext->setText(lineEdit->text());
        }
        //根据num找到对应的CheckBox
        QString checkBoxName = QString("checkBox_%1").arg(num);
        QCheckBox * checkBox = findChild<QCheckBox *>(checkBoxName);
        if(checkBox)
            ui->checkBHexSend->setChecked(checkBox->isChecked());
        //发送
         on_btnSendContext_clicked();
    }
}

void Widget::on_SerialData_readyToRead(){
    //读取数据
    QString revMessage = serialPort->readAll();//读所有数据
    if(revMessage != NULL){//当真正有数据的时候
        qDebug() << "revCnt:" << revMessage.size();//读取了多少个字节
        qDebug() << "内容是:" << revMessage;
        if(ui->checkBLine->isChecked())//是否要自动换行
            revMessage.append("\r\n");

        if(ui->checkBHexDisplay->isChecked()){//是否是HEX显示
            //将新接收的数据转化为16进制
            QByteArray tmpHexString =  revMessage.toUtf8().toHex().toUpper();
            //原本textEdit上面的数据已经是16进制了,然后进行拼接就可以了
            QString tmpStringHex = ui->textEditRev->toPlainText();
            //拼接
            tmpHexString = tmpStringHex.toUtf8() + tmpHexString;
            //显示到textEditRev
            ui->textEditRev->setText(QString::fromUtf8(tmpHexString));
        }else {
            qDebug() << "Get Message " << revMessage;
            if(ui->checkBrevTime->checkState() == Qt::Unchecked){//是否显示接收时间
                //没有勾选
                //insertPlainText是不换行的,append是换行的。
                ui->textEditRev->insertPlainText(revMessage);
            }else if(ui->checkBrevTime->checkState() == Qt::Checked){
               // getSystemTime();
                ui->textEditRev->insertPlainText("【" + myTime + "】" +revMessage);
            }
        }
        //处理接收了多少和状态
        readCntTotal += revMessage.size();
        ui->labelRevcnt->setText("Receive:" + QString :: number(readCntTotal));

        //移动光标到末尾
        //让文本框自动滚动到最底部,并确保光标可见。
        ui->textEditRev->moveCursor(QTextCursor::End);
        ui->textEditRev->ensureCursorVisible();
    }
}

void Widget::refreshSerialName(){

   //每次刷新列表需要清理一下comboBox
    ui->comboBox_serialNum->clear();
   //获取所有电脑可用串口列表
   QList<QSerialPortInfo> serialList = QSerialPortInfo::availablePorts();
   //然后把得到的串口放到comboBox_serialNum里面
   for(QSerialPortInfo serialPort : serialList){
       ui->comboBox_serialNum->addItem(serialPort.portName());
   }
   //更新状态
   ui->labelSendStatus->setText("Com Refreshed!");
}

Widget::~Widget()
{
    delete ui;
}

//方法二用控件上面的checkable
void Widget::on_btnCloseOrOpenSerial_clicked(bool checked)
{
     //qDebug() << "checked is:" << checked;
    //判断是打开串口还是关闭串口
    if(checked){//串口没有打开的时候
        qDebug() << "checked is:" << checked;
        //1.选择串口号
        serialPort->setPortName(ui->comboBox_serialNum->currentText());
        //2.配置波特率
        serialPort->setBaudRate(ui->comboBox_boautrate->currentText().toUInt());
        //3.配置数据位
        serialPort->setDataBits(QSerialPort::DataBits(
                                    ui->comboBox_dataBit->currentText().toUInt()));

       // qDebug() << "数据位:" << serialPort->dataBits();
        //4.配置校验位
        switch (ui->comboBox_jiaoyan->currentIndex()) {//用comboBox中的索引去配置
            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.配置停止位?(如果配置失败,默认是1个停止位)
        serialPort->setStopBits(QSerialPort::StopBits(
                                    ui->comboBox_stopBit->currentText().toUInt()));
        //6.配置流控(默认无流控)
        if(ui->comboBox_fileCon->currentText() == "None"){
            serialPort->setFlowControl(QSerialPort::NoFlowControl);
        }

        //7.打开串口
        if(serialPort->open(QIODevice::ReadWrite)){
            qDebug() << "serial open success";
            //打开成功就把groupBox_params那部分给禁止访问
            ui->comboBox_dataBit->setEnabled(false);
            ui->comboBox_fileCon->setEnabled(false);
            ui->comboBox_jiaoyan->setEnabled(false);
            ui->comboBox_stopBit->setEnabled(false);
            ui->comboBox_boautrate->setEnabled(false);
            ui->comboBox_serialNum->setEnabled(false);
            //重新开放groupBoxDownRightLow这部分
            ui->btnSendContext->setEnabled(true);
            ui->lineEditSendContext->setEnabled(true);
            ui->checkBSendInTime->setEnabled(true);
            ui->checkBSendNewwLine->setEnabled(true);
            ui->checkBHexSend->setEnabled(true);
            ui->lineEditTimeEach->setEnabled(true);
            //并把btnCloseOrOpenSerial的打开串口改为关闭串口
            ui->btnCloseOrOpenSerial->setText("关闭串口");
            //同时改变labelSendStatus的状态表示
            ui->labelSendStatus->setText(ui->comboBox_serialNum->currentText()
                                         + "isOpened!");

            qDebug() << "停止位是:" << serialPort->stopBits();
        }else {//打开失败
            //弹窗警告
            QMessageBox msgBox;
            msgBox.setWindowTitle("打开串口失败");
            msgBox.setText("串口可能被占用或者被拔出!");
            msgBox.exec();
        }
    }else {//关闭串口,操作与上面相反
        serialPort->close();
        //判断有没有打勾
        timer->stop();
        ui->checkBSendInTime->setCheckState(Qt::Unchecked);//去掉打勾
        //禁止访问groupBoxDownRightLow
        ui->btnSendContext->setEnabled(false);
        ui->lineEditSendContext->setEnabled(false);
        ui->checkBSendInTime->setEnabled(false);
        ui->checkBSendNewwLine->setEnabled(false);
        ui->checkBHexSend->setEnabled(false);
        ui->lineEditTimeEach->setEnabled(false);
        //重新开放groupBox_params
        ui->comboBox_dataBit->setEnabled(true);
        ui->comboBox_fileCon->setEnabled(true);
        ui->comboBox_jiaoyan->setEnabled(true);
        ui->comboBox_stopBit->setEnabled(true);
        ui->comboBox_boautrate->setEnabled(true);
        ui->comboBox_serialNum->setEnabled(true);

        //并把btnCloseOrOpenSerial的关闭串口改为打开串口
        ui->btnCloseOrOpenSerial->setText("打开串口");
        //同时改变labelSendStatus的状态表示
        ui->labelSendStatus->setText(ui->comboBox_serialNum->currentText()
                                     + " isClosed!");
        //判断有没有打勾
        buttonsConTimer->stop();
        ui->checkBox_send->setChecked(false);
        ui->spinBox->setEnabled(true);
    }
}

void Widget::on_btnSendContext_clicked()
{
    int writeCnt = 0;//接收write返回值
    //获取lineEditSendContext上面的内容,并且转换为本地的编码
    //下面的转化方式有问题,如果是发长数据,连续发的话可能有重复这是因为转换的时候,
    //可能出现一些误差转换
   // const char * sendData = ui->lineEditSendContext->text().toStdString().c_str();
    //转为本地8位的
    const char * sendData = ui->lineEditSendContext->text().toLocal8Bit().constData();
    if(ui->checkBHexSend->isChecked()){//判断是不是16进制发送(//16进制发送)
        //获得lineEditSendContext里面要发送的内容
        //补充:如果此时勾选了要发送的16进制,此时lineEditSendContext的数据要一定是16进制形式的数据
        QString tmp = ui->lineEditSendContext->text();
        //判断是不是偶数位
        QByteArray tmpArray = tmp.toLocal8Bit();//是不是61 或者 01 02 这种形式
        if(tmpArray.size() % 2 != 0){
            ui->labelSendStatus->setText("Error Input!");
            return;
        }
        //判断此时的数据是不是符合16进制格式,范围是在0-9a-f的数据
        for(char c: tmpArray){
            //isxdigit用于判断一个字符是否是十六进制数字字符。
            if(!std::isxdigit(c)){//判断是不是是十六进制
                ui->labelSendStatus->setText("Error Input!");
                return;
            }
        }

        //判断是否要发送新行(证明此时的数据是16进制,再加新行)
        if(ui->checkBSendNewwLine->isChecked()){
            tmp.append("\r\n");
        }
        //发送出去
        //转换成16进制发送,用户输入01,变成16进制的1,拒绝变成字符1,ASSII 49
        //将用户输入的16进制字符串(如"01")转换成真正的二进制数据(0x01)
        QByteArray arraySend = QByteArray::fromHex(tmpArray);
        writeCnt = serialPort->write(arraySend);
    }else {
        //非16进制发送
        if(ui->checkBSendNewwLine->isChecked()){//是否勾选发送新行
            //勾选了发送新行
            //重新构建sendData
            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 {//发送成功
        ui->labelSendStatus->setText("Send OK!");//发送成功
        writeCntTotal += writeCnt;//累加字节
        //打印出来
        qDebug() << "Send OK " << sendData << "cnt:" << writeCnt;
        //记录到ui上面
        ui->labelSendcnt->setText("Send:" + QString :: number(writeCntTotal));
        writeCnt = 0;//清零
        //把内容记录到历史记录,但是不可以连续重复发送
        if(strcmp(sendData,sendBak.toStdString().c_str()) != 0){
            //说明不可以连续重复发送
            ui->textEditRecord->append(sendData);
//            sendBak = QString(sendData);//加入到临时变量
            sendBak = QString::fromUtf8(sendData);

            ui->textEditRecord->moveCursor(QTextCursor::End);
            ui->textEditRecord->ensureCursorVisible();
        }
    }
}

void Widget::on_checkBSendInTime_clicked(bool checked)
{
    if(checked){
        //勾选了
        //勾选了定时发送,就要禁用btnSendContext和lineEditTimeEach
        //定时发送的时候,框内的内容不能改
        ui->btnSendContext->setEnabled(false);
        ui->lineEditTimeEach->setEnabled(false);
        //设置超时时间,启动定时器
        timer->start(ui->lineEditTimeEach->text().toInt());
    }else {
        //相反操作
        ui->btnSendContext->setEnabled(true);
        ui->lineEditTimeEach->setEnabled(true);
        timer->stop();
    }
}

void Widget::on_btnrevSave_clicked()
{
    //用QFileDialog
    QString fileName = QFileDialog::getSaveFileName(this,
         tr("Save File"), "D:/CPPandQt/serialData.txt", tr("Save File (*.txt)"));

    if(fileName != NULL){
        QFile file;
        file.setFileName(fileName);
        if(!file.open(QIODevice::WriteOnly | QIODevice::Text))return;
        QTextStream out(&file);
        out.setCodec("UTF-8");
        out << ui->textEditRev->toPlainText();
        file.close();
    }
}

void Widget::time_refresh()
{
    getSystemTime();//每隔100ms获得一次时间
    ui->labelCurrentTime->setText(myTime);
}

void Widget::getSystemTime(){
    //获取系统当前时间
    QDateTime currentTime = QDateTime::currentDateTime();
    //获得当前日期
    QDate date = currentTime.date();
    int year = date.year();
    int month = date.month();
    int day = date.day();
    //获得当前时间
    QTime time = currentTime.time();
    int hour = time.hour();
    int min = time.minute();
    int sec = time.second();

    //构建时间
    myTime = QString("%1-%2-%3 %4:%5:%6")
                    .arg(year,2,10,QChar('0'))
                    .arg(month,2,10,QChar('0'))
                    .arg(day,2,10,QChar('0'))
                    .arg(hour,2,10,QChar('0'))
                    .arg(min,2,10,QChar('0'))
                    .arg(sec,2,10,QChar('0'));


    saveTextsTime = 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(min,2,10,QChar('0'))
            .arg(sec,2,10,QChar('0'));

}

void Widget::on_btnrevClear_clicked()
{
    //清空接收区
    ui->textEditRev->setText("");
}

void Widget::on_btnhideTab_clicked(bool checked)
{
    //隐藏面板(隐藏多文本)
    //qDebug() << "隐藏历史"  << checked;
    if(checked){
        ui->groupBoxTexts->hide();
        ui->btnhideTab->setText("拓展面板");
    }else {
        ui->groupBoxTexts->show();
        ui->btnhideTab->setText("隐藏面板");
    }
}

void Widget::on_btnHideHistory_clicked(bool checked)
{
    //隐藏历史(隐藏历史)
    if(checked){
        ui->groupBoxRecord->hide();
        ui->btnHideHistory->setText("拓展历史");
    }else {
        ui->groupBoxRecord->show();
        ui->btnHideHistory->setText("隐藏历史");
    }
}

void Widget::on_checkBHexDisplay_clicked(bool checked)
{
    if(checked){//判断有没有勾选HEX显示
        //1.读取textEdit上面的数据
        QString tmp = ui->textEditRev->toPlainText();
        //2.转成QByteArray,因为QString不能直接16进制
        QByteArray qtmp = tmp.toUtf8();//将字符串转换为UTF-8编码的字符数组
        qtmp = qtmp.toHex();//转换为十六进制。
        //3.显示
        QString lastShow;
        tmp = QString::fromUtf8(qtmp);//将字节数组转换回字符串
        for(int i = 0;i < tmp.size();i += 2){
            lastShow += tmp.mid(i,2) + " ";
        }
        ui->textEditRev->setText(lastShow.toUpper());
    }else {
        //读取texteditRev上面的数据,都是HEX的形式的
        QString tmpHexString = ui->textEditRev->toPlainText();
        //转换为QByteArray
        QByteArray qtmpHexString = tmpHexString.toUtf8();
        //转换为ASCII的形式
        QByteArray tmpQByteString = QByteArray::fromHex(qtmpHexString);//十六进制文本转换回原始二进制
        //写回去textEditRev上面
        ui->textEditRev->setText(QString::fromUtf8(tmpQByteString));

        //小结一下:
//        toUtf8()将字符串转换为UTF-8编码的字节数组。
//        fromUtf8()(静态)	将UTF-8编码的字节数组转换回字符串。是toUtf8()的逆操作。
//        toHex()将原始二进制数据转换为十六进制文本形式
//        fromHex()(静态)将十六进制文本转换回原始二进制数据。是toHex()的逆操作。
    }
}
void Widget::buttons_handler(){
    //每隔一段时间触发定时器超时信号,不用循环(前提是勾选循环发送)
    if(buttons.size() > buttonIndex){
        emit buttons[buttonIndex]->click();//手动点击pushbutton
        buttonIndex++;
    }else {
        buttonIndex = 0;
    }

}

//用定时器解决多文本循环发送
void Widget::on_checkBox_send_clicked(bool checked)
{
    if(checked){
        //点击了循环发送的时候,不能更改spinBox里面的值
        ui->spinBox->setEnabled(false);
        //开始定时器
        buttonsConTimer->start(ui->spinBox->text().toInt());
    }else {
        //和上述相反操作
        ui->spinBox->setEnabled(true);
        buttonsConTimer->stop();
    }
}

//用线程解决多文本循环发送
/*void Widget::on_checkBox_send_clicked(bool checked)
{
    if(checked){
        //点击了循环发送的时候,不能更改spinBox里面的值
        ui->spinBox->setEnabled(false);
        //启动线程
        c1->start();
    }else {
        //和上述相反操作
        ui->spinBox->setEnabled(true);
        c1->terminate();
    }
}*/
//void Widget::on_checkBox_send_clicked(bool checked)
//{
//    //勾选了循环发送了情况,这里的循环发大概意思是在多文本,点发,隔一段时间,点发那里的文本框
//    if(checked){
//        //通过数组buttons拿出pushButton
//        for(int i = 0;i < buttons.size();i++){
//            QPushButton* btnTmp = buttons[i];
//            //手动触发点击信号
//            emit btnTmp->click();
//            //延时一段时间
//            QThread::msleep(ui->spinBox->text().toUInt());
//             //我们不能在QT的UI线程中延时,否则导致页面刷新问题!
//        }
//    }else {

//    }
//}

//实现重置功能
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);
     int ret = msgBox.exec();
     //clickedButton是确认是那个按钮被按下
     if(msgBox.clickedButton() == yesButton){
         qDebug() << "yesButton";
         for(int i = 0;i < lineEdits.size();i++){
             //遍历lineEdit,并清空内容
             lineEdits[i]->clear();
             //遍历checkBox,并取消勾选
             checkBoxs[i]->setChecked(false);
         }
     }else if(msgBox.clickedButton() == noButton){
         qDebug() << "noButton";
     }
}
//载入指令集合
void Widget::on_btnLoad_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this,
         tr("打开文件"), "D:/CPPandQt", tr("文件类型 (*.txt)"));

    //判空
    if(fileName != NULL){
        //打开文件
        QFile file(fileName);
        if(!file.open(QIODevice::ReadOnly | QIODevice::Text))return;
        QTextStream in(&file);
        in.setCodec("UTF-8");
        //一行一行去读
        int i = 0;//索引
        while (!in.atEnd() && i < 9) {//防止i超过lineEdits和checkBoxs的范围
            QString line = in.readLine();
            //分割字符串 重点是","
            QStringList parts = line.split(",");
            //防止出现只打勾HEX,后面lineEdit没有文本的情况
            if(parts.count() == 2){//count返回列表中字符串元素的数量
                lineEdits[i]->setText(parts[1]);
                checkBoxs[i]->setChecked(parts[0].toInt());
            }
            i++;
        }
        file.close();
    }
}

void Widget::on_btnSave_clicked()
{
    //保存指令的文件格式为sendList_后面应该跟对应的时间
    QString round_name = QString("D:/CPPandQt/sendList_");
    round_name.append(saveTextsTime);

    QString fileName = QFileDialog::getSaveFileName(this,
         tr("保存文件"),round_name, tr("文件类型 (*.txt)"));

    QFile file(fileName);
    if(!file.open(QIODevice::WriteOnly | QIODevice::Text))return;

    QTextStream out(&file);
    out.setCodec("UTF-8");
    for(int i = 0;i < lineEdits.size();i++){
        out << checkBoxs[i]->isChecked() << "," << lineEdits[i]->text() << "\n";
    }
    file.close();
}

2.2 在widget.h中

cpp 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QCheckBox>
#include <QLineEdit>
#include <QPushButton>
#include <QSerialPort>
#include <QWidget>

#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_btnCloseOrOpenSerial_clicked(bool checked);

    void on_SerialData_readyToRead();

    void on_btnSendContext_clicked();

    void on_checkBSendInTime_clicked(bool checked);

    void on_btnrevSave_clicked();

    void time_refresh();

    void on_btnrevClear_clicked();

    void on_btnhideTab_clicked(bool checked);

    void on_btnHideHistory_clicked(bool checked);

    void on_checkBHexDisplay_clicked(bool checked);
    void refreshSerialName();

    void on_command_button_click();

    void on_checkBox_send_clicked(bool checked);

    void buttons_handler();

    void on_btnInit_clicked();

    void on_btnLoad_clicked();

    void on_btnSave_clicked();

private:
    Ui::Widget *ui;

    QSerialPort *serialPort;
    int writeCntTotal;
    int readCntTotal;
    QString sendBak;//临时变量
    QTimer * timer;
    void getSystemTime();
    QString myTime;
    QTimer * buttonsConTimer;//这个定时器用于循环发送
    QList<QPushButton *> buttons;//用于保存按钮
    QList<QLineEdit *>lineEdits;//用于保存lineEdit
    QList<QCheckBox *>checkBoxs;//用于保存checkBox
    int buttonIndex;

    customthread* c1;

    QString saveTextsTime;
};
#endif // WIDGET_H

2.3 在mycombobox.cpp

cpp 复制代码
#include "mycombobox.h"

#include <QComboBox>


mycombobox::mycombobox(QWidget *parent) : QComboBox(parent)
{

}

void mycombobox::mousePressEvent(QMouseEvent *event)//重写鼠标事件
{
    if(event->button() == Qt::LeftButton){
        emit refresh();//就发送刷新信号
    }
    QComboBox::mousePressEvent(event);
    /*
        如果是左键点击时:
        先执行自定义代码:emit refresh()(发射刷新信号)
        然后执行 QComboBox::mousePressEvent(e):弹出下拉列表

        如果是其他按键(右键、中键等):
        跳过 if 块(不发射刷新信号)
        直接执行 QComboBox::mousePressEvent(e):执行默认处理(默认处理)
    */
}

2.4 在mycombobox中

cpp 复制代码
#ifndef MYCOMBOBOX_H
#define MYCOMBOBOX_H

#include <QComboBox>
#include <QMouseEvent>
#include <QWidget>

class mycombobox : public QComboBox
{
    Q_OBJECT
public:
    explicit mycombobox(QWidget *parent = nullptr);

signals:
    void refresh();
protected:
    void mousePressEvent(QMouseEvent *event) override;

};

#endif // MYCOMBOBOX_H

2.5 在customthread.cpp

cpp 复制代码
#include "customthread.h"


customthread::customthread(QWidget *parent) : QThread(parent)
{

}

void customthread::run()
{
    while(true){
        emit threadTimeout();
        msleep(1000);
    }

}

2.6 在customthread.h

cpp 复制代码
#ifndef CUSTOMTHREAD_H
#define CUSTOMTHREAD_H

#include <QThread>
#include <QWidget>

class customthread : public QThread
{
    Q_OBJECT
public:
    customthread(QWidget* parent);

protected:
    void run() override;

signals:
    void threadTimeout();
};

#endif // CUSTOMTHREAD_H
相关推荐
小尧嵌入式4 小时前
深入理解C/C++指针
java·c语言·开发语言·c++·qt·音视频
零小陈上(shouhou6668889)4 小时前
增加PyQt5界面的交通流量预测(模型为CNN_GRU,CNN_BiGRU_ATTENTION,LSTM,Python代码)
qt·cnn·gru
繁星蓝雨5 小时前
Qt优雅的组织项目结构一(使用pri进行模块化配置)——————附带详细示例代码
开发语言·qt·pri
繁星蓝雨6 小时前
Qt优雅的组织项目结构二(基于Qt5使用CmakeList进行模块化配置)——————附带详细示例代码
开发语言·qt·cmake·cmakefile.txt·.cmake
edjxj7 小时前
解决QT可执行文件在不同缩放大小的电脑上显示差异
服务器·数据库·qt
IOT-Power15 小时前
QT TCP 源码结构框架
qt
Java Fans15 小时前
Qt Designer 和 PyQt 开发教程
开发语言·qt·pyqt
开始了码16 小时前
深入理解回调函数:从概念到 Qt 实战
开发语言·qt
世转神风-21 小时前
qt-pro文件名词解释
开发语言·qt