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
相关推荐
用户805533698032 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner2 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz7 天前
QML Hello World 入门示例
qt
xcyxiner10 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner11 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner11 天前
DicomViewer (添加模型类)3
qt
xcyxiner12 天前
DicomViewer (目录调整) 2
qt
xcyxiner12 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
桥田智能14 天前
桥田智能 QT-650S:面向白车身焊装的 800kg 重载快换解决方案
开发语言·qt·系统架构
森G14 天前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt