代码拉取完成,页面将自动刷新
同步操作将从 梦之往兮/上位机 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include <QDebug>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <QTimer>
#include <QString>
#include "qcustomplot.h"
#include <realtimedatawidget.h>
#include "form.h"
#include "ui_form.h"
#include "parsedDataWindow.h"
#include <QtUiTools/QUiLoader>
#include <QFile>
#include "SendMessageThread.h"
#include <QSerialPort>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
, receivedData(""),
dataWidget_AD(nullptr),
dataWidget_DTV(nullptr),
dataWidget_Pi(nullptr)
{
ui->setupUi(this);
setWindowTitle("串口调试助手");
// 设置窗口图标
QIcon icon(":image/favicon.ico"); // 使用资源文件中的图标
setWindowIcon(icon);
//设置窗口大小
resize(1500, 700); // 设置窗口大小为宽800像素,高600像素
//设置中心部件
//setCentralWidget(ui->textEdit);
connect(ui->pushButton_plot, &QPushButton::clicked, this, &MainWindow::showForm);
// 关闭TextEdit的自动回车功能
ui->textEdit->setWordWrapMode(QTextOption::NoWrap);
ui->textEdit->setLineWrapMode(QTextEdit::NoWrap);
ui->textEdit_2->setWordWrapMode(QTextOption::NoWrap);
ui->textEdit_2->setLineWrapMode(QTextEdit::NoWrap);
// 获取可用串口列表并添加到下拉列表框
foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
{
QSerialPort serial;
QSerialPortInfo qinfo;
serial.setPort(info);
if(serial.open(QIODevice::ReadWrite))
{
ui->comboBox_PortName->addItem(serial.portName());
serial.close();
}
}
// 在窗体初始化或者构造函数中设置comboBox_PortName的初始选择
ui->comboBox_PortName->setCurrentText("COM2");
// 获取系统支持的波特率列表
QList<qint32> baudRates = QSerialPortInfo::standardBaudRates();
// 遍历每个波特率并添加到ComboBox中
foreach(qint32 baudRate, baudRates) {
ui->comboBox_Boud->addItem(QString::number(baudRate));
}
connect(ui->comboBox_Boud,static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [=](){
QString string_com=ui->comboBox_Boud->currentText();
qDebug() << "Boud is:"<<string_com;
});
//默认串口
ui->comboBox_Boud->setCurrentText("9600");
// 创建串口对象
QSerialPort * serial = new QSerialPort;
// 配置串口参数
connect(ui->open,&QPushButton::clicked,this, [=](){
QString string_com = ui->comboBox_PortName->currentText();
qint32 baudRate =ui->comboBox_Boud->currentText().toInt();
// 配置串口参数
serial->setPortName(string_com); // 设置串口名称
serial->setBaudRate(baudRate); // 设置波特率
serial->setDataBits(QSerialPort::Data8); // 设置数据位
serial->setParity(QSerialPort::NoParity); // 设置奇偶校验位
serial->setStopBits(QSerialPort::OneStop); // 设置停止位
serial->setFlowControl(QSerialPort::NoFlowControl); // 设置流控制
qDebug() << "com is:"<<string_com;
qDebug() << "baudRate is:"<<baudRate;
// 打开串口
if (serial->open(QIODevice::ReadWrite)) {
qDebug() << "Serial port opened!\r\n";
ui->textEdit_2 -> append("Serial port opened successfully!\r");
// 在添加新文本后,确保 QTextEdit 自动滚动到最后
ui->textEdit_2->ensureCursorVisible();
} else {
qDebug() << "Failed to open serial port!";
ui->textEdit_2 -> append("Failed to open serial port!\r");
// 在添加新文本后,确保 QTextEdit 自动滚动到最后
ui->textEdit_2->ensureCursorVisible();
}
}
);
// 设置串口的读写缓冲区大小为 4096 字节
serial->setReadBufferSize(4096);
//关闭串口
connect(ui->close,&QPushButton::clicked,this, [=](){
serial->close();
qDebug() << "Serial port Close!\r\n";
ui->textEdit_2 -> append("Serial port Close!\r");
// 在添加新文本后,确保 QTextEdit 自动滚动到最后
ui->textEdit_2->ensureCursorVisible();
}
);
// 假设`serial`是你的QSerialPort对象的名称
SendMessageThread *sendThread = new SendMessageThread(serial, ui,this);
// 连接按钮点击事件的槽函数
connect(ui->send, &QPushButton::clicked, sendThread, &SendMessageThread::sendMessage);
// 连接按钮点击事件的槽函数
connect(ui->send, &QPushButton::clicked, [=]() {
if (!sendThread->isRunning()) {
sendThread->start();
qDebug() << "Thread started.";
} else {
qDebug() << "Thread is already running.";
}
});
// 连接按钮点击事件的槽函数
connect(sendThread, &SendMessageThread::messageSent, this, [=](const QString &message) {
ui->textEdit_2->append(message); // 将消息追加到文本编辑器中
ui->textEdit_2->ensureCursorVisible(); // 确保滚动到最后
});
// 清除TextEdit中的内容
connect(ui->clearGet,&QPushButton::clicked,this, [=]()
{
// 清除TextEdit中的内容
ui->textEdit->clear();
}
);
//打开实时数据
connect(ui->pushButton_OPenRealData,&QPushButton::clicked,this, [=]()
{
if(serial-> isOpen()){
QByteArray sendData;
// 在sendData的开头插入"W A001 U"
sendData.append("SHOW#\r\n");// 添加回车
serial->write(sendData);
ui->textEdit_2 -> append(sendData);
// 在添加新文本后,确保 QTextEdit 自动滚动到最后
ui->textEdit_2->ensureCursorVisible();
}else
{
ui->textEdit_2 -> append("ERROR: Serial port Close!\r");
// 在添加新文本后,确保 QTextEdit 自动滚动到最后
ui->textEdit_2->ensureCursorVisible();
// 处理文件无法打开的情况
QMessageBox::warning(this, tr("Error"), tr("请打开串口~"));
}
}
);
//关闭实时数据
connect(ui->pushButton_ShutDownRealData,&QPushButton::clicked,this, [=]()
{
if(serial-> isOpen()){
QByteArray sendData;
// 在sendData的开头插入"W A001 U"
sendData.append("SHUT#\r\n");// 添加回车
serial->write(sendData);
ui->textEdit_2 -> append(sendData);
// 在添加新文本后,确保 QTextEdit 自动滚动到最后
ui->textEdit_2->ensureCursorVisible();
}else
{
ui->textEdit_2 -> append("ERROR: Serial port Close!\r");
// 在添加新文本后,确保 QTextEdit 自动滚动到最后
ui->textEdit_2->ensureCursorVisible();
QMessageBox::warning(this, tr("Error"), tr("请打开串口~"));
}
}
);
// 设置 QTextEdit 的样式表
// ui->textEdit->setStyleSheet("QTextEdit textEdit { line-height: 5px; }");
// 连接串口信号 readyRead 到槽函数 readData
// 在类的构造函数或初始化函数中连接信号和槽
connect(serial, &QSerialPort::readyRead, this, [=]() {
QByteArray newData = serial->readAll(); // 读取新的数据
// 将新的数据追加到已接收的数据中
receivedData += newData;
// 检查已接收的数据中是否包含完整的一行
int lineEndIndex;
while ((lineEndIndex = receivedData.indexOf("\r\n")) != -1) {
// 如果找到完整的一行数据,提取并处理该行数据
QString line = receivedData.left(lineEndIndex);
receivedData = receivedData.mid(lineEndIndex + 2); // 移除已处理的数据
// 保存当前光标位置
QTextCursor cursor = ui->textEdit->textCursor();
int position = cursor.position();
// 获取光标在视图中的位置信息
QScrollBar *vScrollBar = ui->textEdit->verticalScrollBar();
int vScrollBarPos = vScrollBar->value();
bool cursorAtEnd = (position == ui->textEdit->document()->characterCount() - 1); // 检查光标是否在最后一行
// 将文本添加到末尾
ui->textEdit->moveCursor(QTextCursor::End);
ui->textEdit->insertPlainText(line + "\r\n");
// 如果光标在末尾,将光标移动到末尾
if (cursorAtEnd) {
ui->textEdit->moveCursor(QTextCursor::End);
} else {
// 否则,恢复光标位置
cursor.setPosition(position);
ui->textEdit->setTextCursor(cursor);
}
// 如果滚动条在最下面,则将视图滚动到最后一行
if (vScrollBar->value() == vScrollBar->maximum()) {
vScrollBar->setValue(vScrollBar->maximum());
} else {
// 否则,恢复滚动条位置
vScrollBar->setValue(vScrollBarPos);
}
// 确保光标可见
ui->textEdit->ensureCursorVisible();
// 调用解析函数解析数据
QMap<QString, QString> parsedData = parseData(line, QStringList() << "AD" << "DTV"
<< "SV"<<"Vi"<<"Ii"<<"Pi"<<"AMP"<<"PF"<<"HJ"<<"PT"
);
// 重新打印解析后的数据
printParsedData(parsedData);
}
});
// //获取当前参数
connect(ui->pushButton_getParameter, &QPushButton::clicked, this, [=]() {
// 处理文件无法打开的情况
QMessageBox::warning(this, tr("Error"), tr("还未开发!!!"));
});
//保存数据
connect(ui->actionsave_data, &QAction::triggered, this, &MainWindow::saveTextEditToFile);
// Only create new widgets if they don't exist yet
if (!dataWidget_AD) {
dataWidget_AD = new RealTimeDataWidget(this); // Change parent to dialog
dataWidget_AD->setYAxisLabel("AD");
dataWidget_AD->hide();
}
if (!dataWidget_DTV) {
dataWidget_DTV = new RealTimeDataWidget(this); // Change parent to dialog
dataWidget_DTV->setYAxisLabel("DTV");
dataWidget_DTV->hide();
}
if (!dataWidget_Pi) {
dataWidget_Pi = new RealTimeDataWidget(this); // Change parent to dialog
dataWidget_Pi->setYAxisLabel("Pi");
dataWidget_Pi->hide();
}
}
MainWindow::~MainWindow()
{
delete ui;
delete serial;
delete dataWidget_AD;
delete dataWidget_DTV;
delete dataWidget_Pi;
}
// parseData 函数的实现
QMap<QString, QString> MainWindow::parseData(const QString &data, const QStringList &keys) {
QMap<QString, QString> parsedData;
// 使用正则表达式匹配键值对
QRegularExpression regex("(\\b\\w+\\b)\\s*:\\s*(\\S+)"); // 匹配键和值,键是由单词字符组成的单词,值可以是任何非空白字符
QRegularExpressionMatchIterator matchIterator = regex.globalMatch(data);
// 遍历匹配结果
while (matchIterator.hasNext()) {
QRegularExpressionMatch match = matchIterator.next();
if (match.hasMatch()) {
QString key = match.captured(1); // 提取键
QString value = match.captured(2); // 提取值
if (keys.contains(key)) {
parsedData[key] = value;
}
}
}
return parsedData;
}
void MainWindow::printParsedData(const QMap<QString, QString> &parsedData) {
// 输出解析结果
QMapIterator<QString, QString> i(parsedData);
while (i.hasNext()) {
i.next();
//qDebug() << i.key() << ":" << i.value();
// 将解析的数据传递给 RealTimePlotWidget
bool ok;
double value = i.value().toDouble(&ok);
// 获取当前时间戳
QDateTime currentTime = QDateTime::currentDateTime();
double timestamp;
// 如果是第一个数据点,记录下时间戳
if (firstTimestamp.isNull()) {
firstTimestamp = currentTime;
timestamp = 0.0; // 第一个数据点的时间戳为 0
} else {
// 计算相对于第一个数据点的时间戳
timestamp = firstTimestamp.msecsTo(currentTime) / 1000.0; // 毫秒转换为秒
}
if (ok && i.key() == "AD") {
//qDebug() << value;
// // 获取当前时间戳
// QDateTime currentTime = QDateTime::currentDateTime();
// double timestamp;
// // 如果是第一个数据点,记录下时间戳
// if (firstTimestamp.isNull()) {
// firstTimestamp = currentTime;
// timestamp = 0.0; // 第一个数据点的时间戳为 0
// } else {
// // 计算相对于第一个数据点的时间戳
// timestamp = firstTimestamp.msecsTo(currentTime) / 1000.0; // 毫秒转换为秒
// }
dataWidget_AD->addDataPoint(timestamp, value);
}
if (ok && i.key() == "DTV") {
// qDebug() << value;
// // 获取当前时间戳
// QDateTime currentTime = QDateTime::currentDateTime();
// double timestamp;
// // 如果是第一个数据点,记录下时间戳
// if (firstTimestamp.isNull()) {
// firstTimestamp = currentTime;
// timestamp = 0.0; // 第一个数据点的时间戳为 0
// } else {
// // 计算相对于第一个数据点的时间戳
// timestamp = firstTimestamp.msecsTo(currentTime) / 1000.0; // 毫秒转换为秒
// }
dataWidget_DTV->addDataPoint(timestamp, value);
}
if (ok && i.key() == "Pi") {
// qDebug() << value;
// // 获取当前时间戳
// QDateTime currentTime = QDateTime::currentDateTime();
// double timestamp;
// // 如果是第一个数据点,记录下时间戳
// if (firstTimestamp.isNull()) {
// firstTimestamp = currentTime;
// timestamp = 0.0; // 第一个数据点的时间戳为 0
// } else {
// // 计算相对于第一个数据点的时间戳
// timestamp = firstTimestamp.msecsTo(currentTime) / 1000.0; // 毫秒转换为秒
// }
dataWidget_Pi->addDataPoint(timestamp, value);
}
}
}
void MainWindow::showForm()
{
// 创建一个新的窗口对象
QDialog *dialog = new QDialog(this); // 将this指针传递给QDialog的构造函数,使MainWindow成为其父对象
// 使用 Uiloader 加载 UI 文件
QUiLoader loader;
//QString path = QDir::cleanPath(QCoreApplication::applicationDirPath() + QDir::separator() + QString("/form.ui"));
QFile file(":form.ui"); // 替换成您的 UI 文件路径
if (!file.open(QFile::ReadOnly)) {
qDebug() << "Failed to open file:" << file.errorString();
ui->textEdit_2 -> append("UI"+file.errorString()+"\r");
// 在添加新文本后,确保 QTextEdit 自动滚动到最后
ui->textEdit_2->ensureCursorVisible();
// 处理文件无法打开的情况
QMessageBox::warning(this, tr("Error"), tr("ui文件未找到!"));
return;
}
QWidget *formWidget = loader.load(&file, dialog);
file.close();
// 如果加载成功,将表单添加到对话框中
if (formWidget) {
// 设置窗口标题
dialog->setWindowTitle("绘图窗口");
// 创建一个新的布局对象
QVBoxLayout *layout = new QVBoxLayout(dialog);
// // 创建一个实时数据窗口部件
// dataWidget_AD = new RealTimeDataWidget(this);
// //ui->verticalLayout_AD->addWidget(dataWidget_AD);
// dataWidget_AD-> setYAxisLabel("AD");
// dataWidget_DTV = new RealTimeDataWidget(this);
// //ui->verticalLayout_DTV->addWidget(dataWidget_DTV);
// dataWidget_DTV-> setYAxisLabel("DTV");
// 将部件添加到布局中
layout->addWidget(dataWidget_AD);
layout->addWidget(dataWidget_DTV);
layout->addWidget(dataWidget_Pi);
dataWidget_AD->show();
dataWidget_DTV->show();
dataWidget_Pi->show();
// 创建截图按钮
QPushButton *screenshotButton = new QPushButton("截图", dialog);
layout->addWidget(screenshotButton);
// 将布局设置为对话框的布局
dialog->setLayout(layout);
// 设置截图按钮点击事件
connect(screenshotButton, &QPushButton::clicked, [=]() {
// 获取安装目录
QString installDir = QCoreApplication::applicationDirPath();
// 构造默认保存路径
QString defaultPath = installDir + "/myimage";
// 检查目标路径是否存在,如果不存在则创建
QDir dir(defaultPath);
if (!dir.exists()) {
dir.mkpath(".");
}
// 构造默认文件名
int count = 1;
QString defaultFileName;
do {
defaultFileName = QString("image_%1.png").arg(count++);
} while (QFile::exists(defaultPath + "/" + defaultFileName));
// 打开文件保存对话框,让用户选择保存截图的文件名和路径
QString filePath = QFileDialog::getSaveFileName(this, tr("Save Image"), defaultPath + "/" + defaultFileName, tr("Images (*.png)"));
// 如果用户取消了选择,则返回
if (filePath.isEmpty()) {
return;
}
// 截取当前窗口并保存截图到指定路径
QPixmap screenshot = dialog->grab();
screenshot.save(filePath);
// 显示保存路径的信息框
QMessageBox::information(dialog, "截图成功", "已保存截图为 " + filePath);
});
// 设置窗口大小和位置
dialog->resize(800, 800);
dialog->move(100, 100);
// 显示窗口
dialog->show();
} else {
qDebug() << "Failed to load UI file:" << loader.errorString();
}
}
//保存文本
void MainWindow::saveTextEditToFile() {
// 获取安装目录
QString installDir = QCoreApplication::applicationDirPath();
// 构造默认保存路径
QString defaultPath = installDir + "/myfile";
// 创建保存文件的目标文件夹
QDir dir(defaultPath);
if (!dir.exists()) {
if (!dir.mkpath(".")) {
QMessageBox::warning(this, tr("Error"), tr("Failed to create directory."));
return;
}
}
// 打开文件保存对话框,让用户选择保存文件的路径,并设置默认路径
QString filePath = QFileDialog::getSaveFileName(this, tr("Save File"), defaultPath, tr("Text Files (*.txt);;All Files (*)"));
// 检查用户是否取消了文件保存对话框
if (filePath.isEmpty()) {
return;
}
// 获取 QTextEdit 中的文本内容
QString text = ui->textEdit->toPlainText();
// 打开文件(如果文件不存在则创建)
QFile file(filePath);
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream out(&file);
out << text;
file.close();
// 显示保存路径的信息框
QMessageBox::information(this, tr("Save Successful"), tr("File saved successfully at:\n%1").arg(filePath));
} else {
// 处理文件无法打开的情况
QMessageBox::warning(this, tr("Error"), tr("Could not open file for writing."));
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。