Qt+C++串口调试接收发送数据曲线图

news2024/12/24 8:26:42

程序示例精选

Qt+C++串口调试接收发送数据曲线图

如需安装运行环境或远程调试,见文章底部个人QQ名片,由专业技术人员远程协助!

前言

这篇博客针对<<Qt+C++串口调试接收发送数据曲线图>>编写代码,代码整洁,规则,易读。 学习与应用推荐首选。


文章目录

一、所需工具软件

二、使用步骤

        1. 引入库

        2. 代码实现

        3. 运行结果

三、在线协助

一、所需工具软件

1. VS, Qt

2. C++

二、使用步骤

1.引入库

#include <QAction>
#include <QCheckBox>
#include <QDragEnterEvent>
#include <QDebug>
#include <QLineEdit>
#include <QMenu>
#include <QMenuBar>
#include <QtSerialPort/QSerialPort>
#include <QtWidgets/QComboBox>
#include <QtWidgets/QGridLayout>
#include <QtWidgets/QLabel>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QGroupBox>
#include <QTextBrowser>
#include <QtWidgets/QFileDialog>
#include <QTimer>
#include <QtCore/QSettings>
#include <QtCore/QProcess>
#include <QStatusBar>
#include <QSplitter>
#include <data/SerialReadWriter.h>
#include <data/TcpServerReadWriter.h>
#include <data/TcpClientReadWriter.h>
#include <QRadioButton>
#include <QButtonGroup>
#include <data/BridgeReadWriter.h>
#include <QMimeData>
#include <QtSerialPort/QSerialPortInfo>
#include <data/SerialBridgeReadWriter.h>
#include <utils/FileUtil.h>
#include <QTextCodec>

2. 代码实现

代码如下:

void MainWindow::openReadWriter() {
    if (_readWriter != nullptr) {
        _readWriter->close();
        delete _readWriter;
        _readWriter = nullptr;
        emit serialStateChanged(false);
    }

    bool result;

    if (readWriterButtonGroup->checkedButton() == serialRadioButton) {
        _serialType = SerialType::Normal;
        auto settings = new SerialSettings();
        settings->name = serialPortNameComboBox->currentText();
        settings->baudRate = serialPortBaudRateComboBox->currentText().toInt();

        settings->dataBits = (QSerialPort::DataBits) serialPortDataBitsComboBox->currentText().toInt();
        settings->stopBits = (QSerialPort::StopBits) serialPortStopBitsComboBox->currentData().toInt();
        settings->parity = (QSerialPort::Parity) serialPortParityComboBox->currentData().toInt();
        auto readWriter = new SerialReadWriter(this);
        readWriter->setSerialSettings(*settings);
        qDebug() << settings->name << settings->baudRate << settings->dataBits << settings->stopBits
                 << settings->parity;
        result = readWriter->open();
        if (!result) {
            showWarning(tr("消息"), tr("串口被占用或者不存在"));
            return;
        }
        _readWriter = readWriter;
        _serialType = SerialType::Normal;
    } else if (readWriterButtonGroup->checkedButton() == tcpServerRadioButton) {
        _serialType = SerialType::TcpServer;
        auto address = tcpAddressLineEdit->text();
        bool ok;
        auto port = tcpPortLineEdit->text().toInt(&ok);
        if (!ok) {
            showMessage("", tr("端口格式不正确"));
            return;
        }

        auto readWriter = new TcpServerReadWriter(this);
        readWriter->
                setAddress(address);
        readWriter->
                setPort(port);
        qDebug() << address << port;
        result = readWriter->open();
        if (!result) {
            showWarning("", tr("建立服务器失败"));
            return;
        }
        connect(readWriter, &TcpServerReadWriter::currentSocketChanged, this, &MainWindow::updateTcpClient);
        connect(readWriter, &TcpServerReadWriter::connectionClosed, this, &MainWindow::clearTcpClient);
        _readWriter = readWriter;
    } else if (readWriterButtonGroup->checkedButton() == tcpClientRadioButton) {
        _serialType = SerialType::TcpClient;
        auto address = tcpAddressLineEdit->text();
        bool ok;
        auto port = tcpPortLineEdit->text().toInt(&ok);
        if (!ok) {
            showMessage("", tr("端口格式不正确"));
            return;
        }

        auto readWriter = new TcpClientReadWriter(this);
        readWriter->setAddress(address);
        readWriter->setPort(port);

        qDebug() << address << port;
        result = readWriter->open();
        if (!result) {
            showError("", tr("连接服务器失败"));
            return;
        }
        _readWriter = readWriter;
    } else if (readWriterButtonGroup->checkedButton() == serialBridgeRadioButton) {
        _serialType = SerialType::SerialBridge;

        auto settings1 = new SerialSettings();
        settings1->name = serialPortNameComboBox->currentText();
        settings1->baudRate = serialPortBaudRateComboBox->currentText().toInt();

        settings1->dataBits = (QSerialPort::DataBits) serialPortDataBitsComboBox->currentText().toInt();
        settings1->stopBits = (QSerialPort::StopBits) serialPortStopBitsComboBox->currentData().toInt();
        settings1->parity = (QSerialPort::Parity) serialPortParityComboBox->currentData().toInt();

        auto settings2 = new SerialSettings();
        settings2->name = secondSerialPortNameComboBox->currentText();
        settings2->baudRate = secondSerialPortBaudRateComboBox->currentText().toInt();

        settings2->dataBits = (QSerialPort::DataBits) secondSerialPortDataBitsComboBox->currentText().toInt();
        settings2->stopBits = (QSerialPort::StopBits) secondSerialPortStopBitsComboBox->currentText().toInt();
        settings2->parity = (QSerialPort::Parity) secondSerialPortParityComboBox->currentText().toInt();

        auto readWriter = new SerialBridgeReadWriter(this);

        readWriter->setSettings(*settings1, *settings2);
        result = readWriter->open();
        if (!result) {
            showWarning(tr("消息"), QString(tr("串口被占用或者不存在,%1")).arg(readWriter->settingsText()));
            return;
        }

        connect(readWriter, &SerialBridgeReadWriter::serial1DataRead, [this](const QByteArray &data) {
            showSendData(data);
        });

        connect(readWriter, &SerialBridgeReadWriter::serial2DataRead, [this](const QByteArray &data) {
            showReadData(data);
        });

        _readWriter = readWriter;
    } else {
        _serialType = SerialType::Bridge;
        auto settings = new SerialSettings();
        settings->name = serialPortNameComboBox->currentText();
        settings->baudRate = serialPortBaudRateComboBox->currentText().toInt();

        settings->dataBits = (QSerialPort::DataBits) serialPortDataBitsComboBox->currentText().toInt();
        settings->stopBits = (QSerialPort::StopBits) serialPortStopBitsComboBox->currentData().toInt();
        settings->parity = (QSerialPort::Parity) serialPortParityComboBox->currentData().toInt();

        auto address = tcpAddressLineEdit->text();
        bool ok;
        auto port = tcpPortLineEdit->text().toInt(&ok);
        if (!ok) {
            showMessage("", tr("端口格式不正确"));
            return;
        }

        auto readWriter = new BridgeReadWriter(this);

        readWriter->setSettings(*settings, address, static_cast<qint16>(port));
        result = readWriter->open();
        if (!result) {
            showWarning(tr("消息"), tr("串口被占用或者不存在"));
            return;
        }

        connect(readWriter, &BridgeReadWriter::currentSocketChanged,
                this, &MainWindow::updateTcpClient);
        connect(readWriter, &BridgeReadWriter::connectionClosed,
                this, &MainWindow::clearTcpClient);
        connect(readWriter, &BridgeReadWriter::serialDataRead, [this](const QByteArray &data) {
            showSendData(data);
        });
        connect(readWriter, &BridgeReadWriter::tcpDataRead, [this](const QByteArray &data) {
            showReadData(data);
        });

        _readWriter = readWriter;
    }
    connect(_readWriter, &AbstractReadWriter::readyRead,
            this, &MainWindow::readData);


    emit serialStateChanged(result);
}

void MainWindow::closeReadWriter() {
    stopAutoSend();
    if (_readWriter != nullptr) {
        _readWriter->close();
        delete _readWriter;
        _readWriter = nullptr;
    }
    emit serialStateChanged(false);
}

void MainWindow::createConnect() {

    connect(readWriterButtonGroup, QOverload<QAbstractButton *, bool>::of(&QButtonGroup::buttonToggled),
            [=](QAbstractButton *button, bool checked) {
                if (checked && isReadWriterOpen()) {
                    SerialType serialType;
                    if (button == tcpServerRadioButton) {
                        serialType = SerialType::TcpServer;
                    } else if (button == tcpClientRadioButton) {
                        serialType = SerialType::TcpClient;
                    } else if (button == bridgeRadioButton) {
                        serialType = SerialType::Bridge;
                    } else {
                        serialType = SerialType::Normal;
                    }

                    if (serialType != _serialType) {
                        if (showWarning("", tr("串口配置已经改变,是否重新打开串口?"))) {
                            openReadWriter();
                        }
                    }
                }
            });

    connect(this, &MainWindow::serialStateChanged, [this](bool isOpen) {
        setOpenButtonText(isOpen);
        QString stateText;
        if (isOpen) {
            stateText = QString(tr("串口打开成功,%1")).arg(_readWriter->settingsText());
        } else {
            stateText = QString(tr("串口关闭"));
        }
        skipSendCount = 0;
        updateStatusMessage(stateText);
    });

    connect(this, &MainWindow::readBytesChanged, this, &MainWindow::updateReadBytes);
    connect(this, &MainWindow::writeBytesChanged, this, &MainWindow::updateWriteBytes);
    connect(this, &MainWindow::currentWriteCountChanged, this, &MainWindow::updateCurrentWriteCount);

    connect(openSerialButton, &QPushButton::clicked, [=](bool value) {
        if (!isReadWriterOpen()) {
            openReadWriter();
        } else {
            closeReadWriter();
        }
    });

    connect(refreshSerialButton, &QPushButton::clicked, [=] {
        _dirty = true;
        updateSerialPortNames();
    });

    connect(saveReceiveDataButton, &QPushButton::clicked, this, &MainWindow::saveReceivedData);
    connect(clearReceiveDataButton, &QPushButton::clicked, this, &MainWindow::clearReceivedData);

    connect(saveSentDataButton, &QPushButton::clicked, this, &MainWindow::saveSentData);
    connect(clearSentDataButton, &QPushButton::clicked, this, &MainWindow::clearSentData);

    connect(autoSendCheckBox, &QCheckBox::clicked, [this] {
        autoSendTimer->stop();
    });

    connect(loopSendCheckBox, &QCheckBox::stateChanged, [this] {
        _loopSend = loopSendCheckBox->isChecked();
    });

    connect(resetLoopSendButton, &QPushButton::clicked, [this] {
        skipSendCount = 0;
        serialController->setCurrentCount(0);
        emit currentWriteCountChanged(0);
    });

    connect(currentSendCountLineEdit, &QLineEdit::editingFinished, [this] {
        bool ok;
        auto newCount = currentSendCountLineEdit->text().toInt(&ok);
        if (ok) {
            serialController->setCurrentCount(newCount);
        } else {
            currentSendCountLineEdit->setText(QString::number(serialController->getCurrentCount()));
        }
    });

    connect(sendLineButton, &QPushButton::clicked, [this] {
        if (!isReadWriterConnected()) {
            handlerSerialNotOpen();
            return;
        }

        if (autoSendState == AutoSendState::Sending) {
            stopAutoSend();
        } else {
            if (_dirty) {
                _dirty = false;
                _sendType = SendType::Line;
                updateSendData(hexCheckBox->isChecked(), sendTextEdit->toPlainText());
                updateSendType();
            }
            sendNextData();
            startAutoSendTimerIfNeed();
        }

        if (autoSendState == AutoSendState::Sending) {
            sendLineButton->setText(tr("停止"));
        } else {
            resetSendButtonText();
        }
    });

    connect(processTextButton, &QPushButton::clicked, [this] {
        openDataProcessDialog(sendTextEdit->toPlainText());
    });

    connect(clearTextButton, &QPushButton::clicked, [this]{
       sendTextEdit->clear();
    });

    connect(lineReturnButtonGroup, QOverload<QAbstractButton *, bool>::of(&QButtonGroup::buttonToggled),
            [=](QAbstractButton *button, bool checked) {
                if (checked) {
                    if (button == sendRReturnLineButton) {
                        lineReturn = QByteArray("\r");
                    } else if (button == sendNReturnLineButton) {
                        lineReturn = QByteArray("\n");
                    } else {
                        lineReturn = QByteArray("\r\n");
                    }
                }
            });

    connect(autoSendTimer, &QTimer::timeout,
            [this] {
                sendNextData();
            });
    connect(hexCheckBox, &QCheckBox::stateChanged, [this] {
        this->_dirty = true;
    });

    connect(sendTextEdit, &QTextEdit::textChanged, [this] {
        this->_dirty = true;
    });
}

void MainWindow::setOpenButtonText(bool isOpen) {
    if (isOpen) {
        openSerialButton->setText(tr("关闭"));
    } else {
        openSerialButton->setText("打开");
    }
}

void MainWindow::createActions() {
    openAct = new QAction(tr("&打开(&O)"), this);
    openAct->setShortcut(QKeySequence::Open);
    openAct->setStatusTip(tr("打开一个文件"));
    connect(openAct, &QAction::triggered, this, &MainWindow::open);

    saveAct = new QAction(tr("&保存(&S)"), this);
    saveAct->setShortcut(QKeySequence::Save);
    saveAct->setStatusTip(tr("保存一个文件"));
    connect(saveAct, &QAction::triggered, this, &MainWindow::save);

    validateDataAct = new QAction(tr("计算校验(&E)"), this);
    validateDataAct->setShortcut(tr("Ctrl+E"));
    validateDataAct->setStatusTip(tr("计算数据校验值"));
    connect(validateDataAct, &QAction::triggered, this, &MainWindow::openDataValidator);

    convertDataAct = new QAction(tr("数据转换(&T)"));
    convertDataAct->setShortcut(tr("Ctrl+T"));
    convertDataAct->setStatusTip(tr("数据转换"));
    connect(convertDataAct, &QAction::triggered, this, &MainWindow::openConvertDataDialog);

    dataProcessAct = new QAction(tr("数据处理(&P)"));
    dataProcessAct->setShortcut(tr("Ctrl+P"));
    dataProcessAct->setStatusTip(tr("数据处理"));
    connect(dataProcessAct, &QAction::triggered, [this] {
        openDataProcessDialog("");
    });
}

void MainWindow::createMenu() {
    fileMenu = menuBar()->addMenu(tr("文件(&F)"));
    fileMenu->addAction(openAct);
    fileMenu->addAction(saveAct);

    toolMenu = menuBar()->addMenu(tr("工具(&T)"));
    toolMenu->addAction(validateDataAct);
    toolMenu->addAction(convertDataAct);
    toolMenu->addAction(dataProcessAct);
}

void MainWindow::open() {
    auto lastDir = runConfig->lastDir;
    QString fileName = QFileDialog::getOpenFileName(this, tr("打开数据文件"), lastDir, "");
    if (fileName.isEmpty()) {
        return;
    }

    QFile file(fileName);
    if (file.open(QIODevice::ReadOnly)) {
        runConfig->lastDir = getFileDir(fileName);
        auto data = file.readAll();
        sendTextEdit->setText(QString::fromLocal8Bit(data));
    }
}

void MainWindow::save() {
    saveReceivedData();
}

void MainWindow::openDataValidator() {
    CalculateCheckSumDialog dialog(this);
    dialog.setModal(true);
    dialog.exec();
}

void MainWindow::openConvertDataDialog() {
    ConvertDataDialog dialog(this);
    dialog.setModal(true);
    dialog.exec();
}

void MainWindow::openDataProcessDialog(const QString &text) {
    DataProcessDialog dialog(text, this);
    dialog.setModal(true);

    int result = dialog.exec();
    if (result == QDialog::Accepted) {
        sendTextEdit->setText(dialog.text());
    }
}

void MainWindow::displayReceiveData(const QByteArray &data) {

    if (pauseReceiveCheckBox->isChecked()) {
        return;
    }

    static QString s;

    s.clear();

    if (addReceiveTimestampCheckBox->isChecked()) {
        s.append("[").append(getTimestamp()).append("] ");
    }

    if (!s.isEmpty()) {
        s.append(" ");
    }
    if (displayReceiveDataAsHexCheckBox->isChecked()) {
        s.append(dataToHex(data));
    } else {
        s.append(QString::fromLocal8Bit(data));
    }

    if (addLineReturnCheckBox->isChecked() || addReceiveTimestampCheckBox->isChecked()) {
        receiveDataBrowser->append(s);
    } else {
        auto text = receiveDataBrowser->toPlainText();
        text.append(s);
        receiveDataBrowser->setText(text);
        receiveDataBrowser->moveCursor(QTextCursor::End);
    }
}

void MainWindow::displaySentData(const QByteArray &data) {
    if (displaySendDataAsHexCheckBox->isChecked()) {
        sendDataBrowser->append(dataToHex(data));
    } else {
        sendDataBrowser->append(QString::fromLocal8Bit(data));
    }
}

void MainWindow::sendNextData() {
    if (isReadWriterConnected()) {
        if (skipSendCount > 0) {
            auto delay = skipSendCount * sendIntervalLineEdit->text().toInt();
            updateStatusMessage(QString("%1毫秒后发送下一行").arg(delay));
            skipSendCount--;
            return;
        }

        qDebug() << "sendNextData readEnd:" << serialController->readEnd() << "current:"
                 << serialController->getCurrentCount();
        if (!_loopSend && autoSendCheckBox->isChecked() && serialController->readEnd()) {
            serialController->setCurrentCount(0);
            stopAutoSend();
            return;
        }
        auto data = serialController->readNextFrame();
        if (data.isEmpty()) {
            updateStatusMessage(tr("空行,不发送"));
            if (autoSendCheckBox->isChecked()) {
                auto emptyDelay = emptyLineDelayLindEdit->text().toInt();
                auto sendInterval = sendIntervalLineEdit->text().toInt();
                if (emptyDelay > sendInterval) {
                    skipSendCount = emptyDelay / sendInterval;
                    if (emptyDelay % sendInterval != 0) {
                        skipSendCount += 1;
                    }
                    skipSendCount--;
                    updateStatusMessage(QString(tr("空行,%1毫秒后发送下一行")).arg(emptyDelay));
                }
            }
            emit currentWriteCountChanged(serialController->getCurrentCount());
            return;
        }
        writeData(data);
        if (sendLineReturnCheckBox->isChecked()) {
            writeData(lineReturn);
        }
        if (hexCheckBox->isChecked()) {
            updateStatusMessage(QString(tr("发送 %1")).arg(QString(dataToHex(data))));
        } else {
            updateStatusMessage(QString(tr("发送 %1")).arg(QString(data)));
        }
        emit currentWriteCountChanged(serialController->getCurrentCount());
    } else {
        handlerSerialNotOpen();
    }
}

void MainWindow::updateSendData(bool isHex, const QString &text) {
    if (serialController != nullptr) {
        QStringList lines = getLines(text);
        QList<QByteArray> dataList;
        if (isHex) {
            for (auto &line :lines) {
                dataList << dataFromHex(line);
            }
        } else {
            for (auto &line:lines) {
                dataList << line.toLocal8Bit();
            }
        }
        serialController->setData(dataList);
        totalSendCount = serialController->getTotalCount();
        updateTotalSendCount(totalSendCount);
    }
}

void MainWindow::readSettings() {

    qDebug() << "readSettings";

    updateSerialPortNames();

    QSettings settings("Zhou Jinlong", "Serial Wizard");

    settings.beginGroup("Basic");
    auto serialType = SerialType(settings.value("serial_type", static_cast<int >(SerialType::Normal)).toInt());
    if (serialType == SerialType::TcpServer) {
        tcpServerRadioButton->setChecked(true);
    } else if (serialType == SerialType::TcpClient) {
        tcpClientRadioButton->setChecked(true);
    } else if (serialType == SerialType::Bridge) {
        bridgeRadioButton->setChecked(true);
    } else if (serialType == SerialType::SerialBridge) {
        serialBridgeRadioButton->setChecked(true);
    } else {
        serialRadioButton->setChecked(true);
    }

    _serialType = serialType;

    settings.beginGroup("SerialSettings");
    auto nameIndex = settings.value("name", 0).toInt();
    auto baudRateIndex = settings.value("baud_rate", 5).toInt();
    auto dataBitsIndex = (QSerialPort::DataBits) settings.value("data_bits", 3).toInt();
    auto stopBitsIndex = (QSerialPort::StopBits) settings.value("stop_bits", 0).toInt();
    auto parityIndex = (QSerialPort::Parity) settings.value("parity", 0).toInt();
    auto sendText = settings.value("send_text", "").toString();

    auto maxCount = serialPortNameComboBox->maxCount();
    if (nameIndex > maxCount - 1) {
        nameIndex = 0;
    }
    serialPortNameComboBox->setCurrentIndex(nameIndex);
    serialPortBaudRateComboBox->setCurrentIndex(baudRateIndex);
    serialPortDataBitsComboBox->setCurrentIndex(dataBitsIndex);
    serialPortStopBitsComboBox->setCurrentIndex(stopBitsIndex);
    serialPortParityComboBox->setCurrentIndex(parityIndex);

    auto name2Index = settings.value("name2", 0).toInt();
    auto baudRate2Index = settings.value("baud_rate2", 5).toInt();
    auto dataBits2Index = (QSerialPort::DataBits) settings.value("data_bits2", 3).toInt();
    auto stopBits2Index = (QSerialPort::StopBits) settings.value("stop_bits2", 0).toInt();
    auto parity2Index = (QSerialPort::Parity) settings.value("parity2", 0).toInt();

    auto maxCount2 = serialPortNameComboBox->maxCount();
    if (name2Index > maxCount2 - 1) {
        name2Index = 0;
    }
    secondSerialPortNameComboBox->setCurrentIndex(name2Index);
    secondSerialPortBaudRateComboBox->setCurrentIndex(baudRate2Index);
    secondSerialPortDataBitsComboBox->setCurrentIndex(dataBits2Index);
    secondSerialPortStopBitsComboBox->setCurrentIndex(stopBits2Index);
    secondSerialPortParityComboBox->setCurrentIndex(parity2Index);

    settings.beginGroup("SerialReceiveSettings");
    auto addLineReturn = settings.value("add_line_return", true).toBool();
    auto displayReceiveDataAsHex = settings.value("display_receive_data_as_hex", false).toBool();
    auto addTimestamp = settings.value("add_timestamp", false).toBool();

    addLineReturnCheckBox->setChecked(addLineReturn);
    displayReceiveDataAsHexCheckBox->setChecked(displayReceiveDataAsHex);
    addReceiveTimestampCheckBox->setChecked(addTimestamp);

    settings.beginGroup("SerialSendSettings");
    auto sendAsHex = settings.value("send_as_hex", false).toBool();
    auto displaySendData = settings.value("display_send_data", false).toBool();
    auto displaySendDataAsHex = settings.value("display_send_data_as_hex", false).toBool();
    auto autoSend = settings.value("auto_send", false).toBool();
    auto autoSendInterval = settings.value("auto_send_interval", 100).toInt();
    auto emptyLineDelay = settings.value("empty_line_delay", 0).toInt();

    auto loopSend = settings.value("loop_send", false).toBool();

    hexCheckBox->setChecked(sendAsHex);
    displaySendDataCheckBox->setChecked(displaySendData);
    displaySendDataAsHexCheckBox->setChecked(displaySendDataAsHex);
    autoSendCheckBox->setChecked(autoSend);
    loopSendCheckBox->setChecked(loopSend);
    sendIntervalLineEdit->setText(QString::number(autoSendInterval));
    emptyLineDelayLindEdit->setText(QString::number(emptyLineDelay));

    auto sendLineReturn = settings.value("send_line_return", false).toBool();
    sendLineReturnCheckBox->setChecked(sendLineReturn);

    auto sendLineReturnType = LineReturn(
            settings.value("send_line_return_type", static_cast<int >(LineReturn::RN)).toInt());
    if (sendLineReturnType == LineReturn::R) {
        sendRReturnLineButton->setChecked(true);
    } else if (sendLineReturnType == LineReturn::N) {
        sendNReturnLineButton->setChecked(true);
    } else {
        sendRNLineReturnButton->setChecked(true);
    }

    settings.beginGroup("TcpSettings");
    auto ipList = getNetworkInterfaces();
    auto ipAddress = settings.value("tcp_address", "").toString();
    QString selectAddress = "";
    if (!ipAddress.isEmpty() && !ipList.isEmpty()) {
        auto found = false;
        for (const auto &ip:ipList) {
            if (getIpAddress(ip) == ipAddress) {
                selectAddress = ipAddress;
                found = true;
                break;
            }
        }
        if (!found) {
            selectAddress = getIpAddress(ipList.first());
        }
    }
    if (selectAddress.isEmpty()) {
        if (!ipList.isEmpty()) {
            do {
                for (const auto &ip:ipList) {
                    if (ip.type() == QNetworkInterface::Wifi && !getIpAddress(ip).isEmpty()) {
                        selectAddress = getIpAddress(ip);
                        break;
                    }
                }
                if (!selectAddress.isEmpty()) {
                    break;
                }
                for (const auto &ip:ipList) {
                    if (ip.type() == QNetworkInterface::Ethernet && !getIpAddress(ip).isEmpty()) {
                        selectAddress = getIpAddress(ip);
                    }
                }
                if (!selectAddress.isEmpty()) {
                    break;
                }

                selectAddress = getIpAddress(ipList.first());
            } while (false);
        }
    }

    tcpAddressLineEdit->setText(selectAddress);

    auto tcpPort = settings.value("tcp_port").toInt();
    tcpPortLineEdit->setText(QString::number(tcpPort));

    sendTextEdit->setText(sendText);

    settings.beginGroup("RunConfig");
    auto lastDir = settings.value("last_dir", "").toString();
    auto lastFilePath = settings.value("last_file_path", "").toString();

    runConfig = new RunConfig;
    runConfig->lastDir = lastDir;
    runConfig->lastFilePath = lastFilePath;

    _loopSend = loopSend;

    serialController = new LineSerialController();

    updateSendType();
}

3. 运行结果

动画演示

 

三、在线协助:

如需安装运行环境或远程调试,见文章底部个人 QQ 名片,由专业技术人员远程协助!
1)远程安装运行环境,代码调试
2)Qt, C++, Python入门指导
3)界面美化
4)软件制作

当前文章连接:Python+Qt桌面端与网页端人工客服沟通工具_alicema1111的博客-CSDN博客

博主推荐文章:python人脸识别统计人数qt窗体-CSDN博客

博主推荐文章:Python Yolov5火焰烟雾识别源码分享-CSDN博客

                         Python OpenCV识别行人入口进出人数统计_python识别人数-CSDN博客

个人博客主页:alicema1111的博客_CSDN博客-Python,C++,网页领域博主

博主所有文章点这里alicema1111的博客_CSDN博客-Python,C++,网页领域博主

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/911609.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

为何lazada、亚马逊、速卖通卖家都选择自养账号测评?

无论是做亚马逊还是shopee、Lazada、速卖通、wish、煤炉、拼多多Temu、敦煌网、eBay、Etsy、Newegg、美客多、Allegro、阿里国际、poshmark、沃尔玛、joom、OZON等平台。如果想要销量好&#xff0c;免不了进行补单测评的&#xff0c;因为不管对于哪一个平台的店铺新产品而言&am…

探工业互联网的下一站!腾讯云助力智造升级

引言 数字化浪潮正深刻影响着传统工业形态。作为第四次工业革命的重要基石&#xff0c;工业互联网凭借其独特的价值快速崛起&#xff0c;引领和推动着产业变革方向。面对数字化时代给产业带来的机遇与挑战&#xff0c;如何推动工业互联网的规模化落地&#xff0c;加速数字经济…

开利网络受邀参与御盛马术庄园发展专委会主题会议

近日&#xff0c;开利网络受邀参与深度合作客户御盛马术庄园组织的首届发展专委会主体会议&#xff0c;就马术庄园发展方向进行沟通&#xff0c;数字化也是重要议题之一。目前&#xff0c;御盛马术庄园已经完成数字化系统的初步搭建&#xff0c;将通过线上线下相结合的方式搭建…

编写接口文档示例:从零开始,轻松掌握关键技巧

接口文档的编写是软件开发中至关重要的一环&#xff0c;本文将详细介绍如何编写接口文档示例&#xff0c;为您揭示从基础知识到高级技巧的全过程。通过实用的指导和比喻&#xff0c;让您轻松掌握编写接口文档示例的艺术。 在现代软件开发中&#xff0c;编写接口文档示例是确保项…

Linux 上 离线部署GeoScene Server Py3 运行时环境

默认安装ArcGIS Pro的时候&#xff0c;会自动部署上Python3环境&#xff0c;所以在windows上不需要考虑这个问题&#xff0c;但是linux默认并不部署Py3&#xff0c;因此需要单独部署&#xff0c;具体部署可以参考Linux 上 ArcGIS Server 的 Python 3 运行时—ArcGIS Server | A…

PAT(Advanced Level) Practice(with python)——1067 Sort with Swap(0, i)

Code # 输入有毒&#xff0c;需避坑 # N int(input()) L list(map(int,input().split())) N L[0] L L[1:] res 0 for i in range(1,N):while L[0]!0:# 把所有不在正常位置下的数换到正常t L[0]L[0],L[t] L[t],L[0]res1if L[i]!i:# 换完全后如果对应位置下的数不是目标…

【校招VIP】测试专业课之TCP/IP模型

考点介绍&#xff1a; 大厂测试校招面试里经常会出现TCP/IP模型的考察&#xff0c;TCP/IP协议是网络基础知识&#xff0c;但是在校招面试中很多同学在基础回答中不到位&#xff0c;或者倒在引申问题里&#xff0c;就丢分了。 『测试专业课之TCP/IP模型』相关题目及解析内容可点…

免费开源CRM:有哪些免费开源的CRM系统可供选择?

CRM系统是什么 CRM就是客户关系管理系统&#xff0c;简单来说&#xff0c;就是一个要做到集客户管理&#xff0c;产品进销存&#xff0c;订单跟进&#xff0c;数据分析&#xff0c;售后维护为一体的系统。而开源的CRM系统&#xff0c;最基本的含义是代码是公开的&#xff0c;任…

innovus添加pad的命令

我正在「拾陆楼」和朋友们讨论有趣的话题&#xff0c;你⼀起来吧&#xff1f; 拾陆楼知识星球入口 innovus中添加pad需要使用addInst命令创建physical cell&#xff0c;因为pad没有逻辑功能&#xff0c;不存在与网表中&#xff0c;需要自己创建。 添加pad用addInst -inst $pa…

pr剪辑工具绿色版本

免费提供 提取码: 402s Pr提供了采集、剪辑、调色、美化音频、字幕添加、 输出、DVD刻录等一整套流程&#xff0c; 并和其他Adobe 软件高效集成&#xff0c;使您足以完成在编辑、 制作、工作上遇到的所有挑战&#xff0c;满足您创建高质量作品的要求。 Pr的版本选择 常用…

通过浏览器控制台使用js脚本进行浏览器操作(定时点击等)

进行此操作前我们首先需要了解js编程语言 --了解之后我们就可以去操作了 这里我们拿csdn评论举例子&#xff1b; 点开评论界面右键审查元素 此时我们需要找到输入框dom和评论按钮dom 点击元素之后点击箭头然后去界面上选中文本框核按钮 然后我们就可以知道这个文本框的id 同…

没人用还占空间 微软Win11系统将允许卸载更多内置软件

不出意外的话&#xff0c;下个月Win11系统就要迎来Win11 23H2升级了&#xff0c;这是第二个年度更新&#xff0c;带来永不合并任务栏、ZIP解压缩原生支持等新功能。 在推新的同时&#xff0c;微软还要除旧&#xff0c;Win11系统内置了很多应用&#xff0c;一些是集成到系统功能…

ARM汇编【2】:LOAD 和 STORE

ARM使用load-store指令进行内存访问&#xff0c;这意味着只有LDR和STR指令才能访问内存&#xff0c;虽然在X86上&#xff0c;大多数指令都可以对内存中的数据进行操作&#xff0c;但在ARM上&#xff0c;数据在进行操作之前必须从内存移动到寄存器中。这意味着&#xff0c;在ARM…

简单理解Socket

TCP/IP 要想理解socket首先得熟悉一下TCP/IP协议族&#xff0c; TCP/IP&#xff08;Transmission Control Protocol/Internet Protocol&#xff09;即传输控制协议/网间协议&#xff0c;定义了主机如何连入因特网及数据如何再它们之间传输的标准&#xff0c; 从字面意思来看T…

ESD实时监测报警系统主要包括哪些部分

ESD实时监测报警系统是指用于监测静电放电&#xff08;Electrostatic Discharge, ESD&#xff09;并及时报警的系统。静电放电是指物体由于静电积累引起的瞬时放电现象&#xff0c;可能对电子元器件、电子设备等造成潜在的损坏或干扰。 ESD实时监测报警系统通常包括以下几个主…

岩棉革新——洛科威推出NGF新一代岩棉产品

作为全球领先的岩棉制品生产商&#xff0c;洛科威公司基于在岩棉性能革新领域八十多年的深入研究和生产工艺的不断优化&#xff0c;在中国市场正式推出NGF新一代岩棉制品&#xff0c;并在上海国际绿色建筑建材博览会和2023国际绿色低碳技术展上正式发布。 洛科威NGF产品作为革…

bigemap如何批量添加地图?

bigemap如何批量添加地图&#xff1f; 说明&#xff1a;批量添加可以同时添加多个在线地图&#xff0c;一次性添加完成&#xff08;批量添加无法验证地址是否可以访问&#xff09;&#xff08;批量配置文件可以在官网获取&#xff09; 第一步选择地图点进去点(添加号) 第二步&…

QPushbutton

QPushbutton API使用方式 QPushbutton大部分时候都需要使用它从父类QAbstractbutton中继承过来的那些 API。 API // 构造函数 /* 参数:- icon: 按钮上显示的图标- text: 按钮上显示的标题- parent: 按钮的父对象, 可以不指定 */ QPushButton::QPushButton(const QIcon &i…

Python学习 -- 类的封装

当谈及面向对象编程&#xff08;Object-Oriented Programming&#xff0c;OOP&#xff09;&#xff0c;封装是其中的一个重要概念。封装是指将数据和方法封装在一个单一的实体中&#xff0c;以达到隐藏内部实现细节、提供统一接口、提高代码可维护性等目的。在Python中&#xf…

智慧水务在供水行业的应用场景

什么是“智慧水务” 智慧水务指利用物联网、智能传感、云计算、大数据、人工智能等技术对供水、排水、节水、污水 处理、防洪等水务环节进行智慧化管理。智慧水务通过结合传感器、通信网络、水务信息系统提升水务信息化水平&#xff0c;实现水务管理协同化、水资源利用高效化、…