3731 lines
125 KiB
C++
3731 lines
125 KiB
C++
//#if _MSC_VER >= 1600
|
||
//#pragma execution_character_set("utf-8")
|
||
//#endif
|
||
|
||
#include "mainwindow.h"
|
||
#include "ui_mainwindow.h"
|
||
#include <QMessageBox>
|
||
#include <QDebug>
|
||
#include <QPoint>
|
||
#include <QSettings>
|
||
#include <QFileDialog>
|
||
#include <QAbstractScrollArea>
|
||
#include <QScrollBar>
|
||
#include <QStyledItemDelegate>
|
||
#include <QSerialPortInfo>
|
||
#include <QScrollArea>
|
||
#include <QGuiApplication>
|
||
#include <QScreen>
|
||
#include <QRegularExpression>
|
||
#include <QRegularExpressionValidator>
|
||
#include <algorithm> // 添加算法库支持std::sort
|
||
#include <QProgressDialog>
|
||
#include <QtXlsx>
|
||
|
||
#include "commonhelper.h"
|
||
#include "frameless_helper.h"
|
||
#include "sendhistorydialog.h" // 添加发送历史对话框头文件
|
||
#include "xlsxdocument.h"
|
||
#include "xlsxworksheet.h"
|
||
#include "xlsxcellrange.h"
|
||
#include "xlsxsheetmodel.h"
|
||
|
||
using namespace QXlsx;
|
||
|
||
#define BUTTON_REPEAT_INTERVAL 400
|
||
#define COLUMN_MAX 23
|
||
#define COLUMN_VALID 21
|
||
#define COLUMN_SENDBUTTON 22
|
||
|
||
MainWindow::MainWindow(QWidget* parent, ToolkitBase_Interface* pBaseInterface) :
|
||
QMainWindow(parent),
|
||
ui(new Ui::MainWindow)
|
||
{
|
||
ui->setupUi(this);
|
||
|
||
sendCount = 0;
|
||
receiveCount = 0;
|
||
dataSize = 0;
|
||
b_mqtt_connected = false;
|
||
|
||
bSendFile = false;
|
||
updateBuffer = NULL;
|
||
|
||
m_sendHistoryDialog = nullptr; // 初始化发送历史对话框指针
|
||
|
||
// 创建日志记录对象
|
||
m_logRecord = new LogRecord(this);
|
||
|
||
m_serialPort = new QSerialPort(this);
|
||
|
||
timer = new QTimer(this);
|
||
connect(timer, &QTimer::timeout, this, &MainWindow::timerUpdate);
|
||
|
||
sendFileTimer = new QTimer(this);
|
||
connect(sendFileTimer, &QTimer::timeout, this, &MainWindow::sendFileTimerUpdate);
|
||
|
||
PressTimer = new QTimer(this);
|
||
connect(PressTimer, &QTimer::timeout, this, &MainWindow::PressTimerUpdate);
|
||
|
||
// 初始化定时器 - 修改为每秒检查一次
|
||
regularTimer = new QTimer(this);
|
||
isRegularSending = false;
|
||
isPausedSending = false; // 初始化暂停状态变量
|
||
currentCommandIndex = 0;
|
||
elapsedSeconds = 0; // 添加累计秒数计数器
|
||
regularTimer->setInterval(1000); // 固定为1秒间隔
|
||
// 修改连接到新的发送方法
|
||
connect(regularTimer, SIGNAL(timeout()), this, SLOT(sendRegularCommandWithPort()));
|
||
|
||
initUi();
|
||
|
||
// 初始化主界面下拉框
|
||
updatePortsInComboBoxes();
|
||
|
||
connections();
|
||
|
||
QVector<QComboBox*>boxVec;
|
||
boxVec << ui->baudRateComboBox << ui->parityComboBox << ui->dataBitsComboBox
|
||
<< ui->stopBitsComboBox << ui->styleComboBox << ui->comComboBox;
|
||
// 设置代理
|
||
QStyledItemDelegate* delegate = new QStyledItemDelegate(this);
|
||
foreach (QComboBox* comboBox, boxVec)
|
||
{
|
||
comboBox->setItemDelegate(delegate);
|
||
}
|
||
|
||
// 发送文件功能已搭建完成,暂时不开放 2019/1/22
|
||
// ui->label_17->hide();
|
||
// ui->filePathLineEdit->hide();
|
||
// ui->openFileButton->hide();
|
||
// ui->sendFileButton->hide();
|
||
}
|
||
|
||
MainWindow::~MainWindow()
|
||
{
|
||
// 确保程序退出时停止日志记录
|
||
if (m_logRecord->isLogging())
|
||
{
|
||
m_logRecord->stopLog();
|
||
}
|
||
|
||
// 确保停止定时器
|
||
if (m_sendHistoryDialog && m_sendHistoryDialog->isTimingActive())
|
||
{
|
||
m_sendHistoryDialog->stopTimingCount();
|
||
}
|
||
|
||
// 释放发送历史对话框
|
||
if (m_sendHistoryDialog)
|
||
{
|
||
delete m_sendHistoryDialog;
|
||
m_sendHistoryDialog = nullptr;
|
||
}
|
||
|
||
// 关闭和释放所有串口
|
||
for (auto it = m_serialPorts.begin(); it != m_serialPorts.end(); ++it)
|
||
{
|
||
if (it.value()->isOpen())
|
||
{
|
||
it.value()->close();
|
||
}
|
||
delete it.value();
|
||
}
|
||
m_serialPorts.clear();
|
||
|
||
delete ui;
|
||
}
|
||
|
||
bool MainWindow::eventFilter(QObject* obj, QEvent* event)
|
||
{
|
||
if (obj == ui->lblTitle)
|
||
{
|
||
if (event->type() == QEvent::MouseButtonPress)
|
||
{
|
||
QMouseEvent* mouseEvent = dynamic_cast<QMouseEvent*>(event);
|
||
|
||
if (mouseEvent->button() == Qt::LeftButton)
|
||
{
|
||
mousePressed = true;
|
||
mousePoint = mouseEvent->globalPos() - pos();
|
||
mouseEvent->accept();
|
||
|
||
return true;
|
||
}
|
||
}
|
||
|
||
else if (event->type() == QEvent::MouseMove)
|
||
{
|
||
QMouseEvent* mouseEvent = dynamic_cast<QMouseEvent*>(event);
|
||
|
||
if (mousePressed && this->windowState() != Qt::WindowMaximized)
|
||
{
|
||
if (mouseEvent->globalY() <= QGuiApplication::primaryScreen()->availableGeometry().bottom())
|
||
{
|
||
move(mouseEvent->globalPos() - mousePoint);
|
||
mouseEvent->accept();
|
||
}
|
||
else
|
||
{
|
||
QCursor::setPos(
|
||
QCursor::pos().x(),
|
||
QGuiApplication::primaryScreen()->availableGeometry().bottom()
|
||
);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
}
|
||
|
||
else if (event->type() == QEvent::MouseButtonRelease)
|
||
{
|
||
QMouseEvent* mouseEvent = dynamic_cast<QMouseEvent*>(event);
|
||
|
||
if (mouseEvent->button() == Qt::LeftButton)
|
||
{
|
||
mousePressed = false;
|
||
mouseEvent->accept();
|
||
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
|
||
return QObject::eventFilter(obj, event);
|
||
}
|
||
|
||
void MainWindow::on_btnCloseMenu_clicked()
|
||
{
|
||
close();
|
||
}
|
||
|
||
void MainWindow::on_btnMinMenu_clicked()
|
||
{
|
||
showMinimized();
|
||
}
|
||
|
||
// void MainWindow::openSerialPort()
|
||
// {
|
||
// // 先关闭可能已经打开的串口
|
||
// if (m_serialPort->isOpen()) {
|
||
// m_serialPort->close();
|
||
// QThread::msleep(100); // 等待串口完全关闭
|
||
// }
|
||
|
||
// // 更新串口配置
|
||
// updateComSettings();
|
||
|
||
// // 检查串口名称是否有效
|
||
// if (currentSettings.name.isEmpty()) {
|
||
// CommonHelper::ShowMessageBoxError(tr("串口名称无效,请重新选择串口!"));
|
||
// return;
|
||
// }
|
||
|
||
// // 设置串口参数
|
||
// m_serialPort->setPortName(currentSettings.name);
|
||
// m_serialPort->setBaudRate(currentSettings.baudRate);
|
||
// m_serialPort->setDataBits(currentSettings.dataBits);
|
||
// m_serialPort->setParity(currentSettings.parity);
|
||
// m_serialPort->setStopBits(currentSettings.stopBits);
|
||
// m_serialPort->setFlowControl(QSerialPort::NoFlowControl);
|
||
|
||
// // 尝试打开串口
|
||
// if (m_serialPort->open(QIODevice::ReadWrite))
|
||
// {
|
||
// // 更新UI状态
|
||
// ui->connectInfo->setPixmap(QPixmap(":/skin/image/info.png"));
|
||
// ui->connectInfo->setScaledContents(true);
|
||
// ui->connectBtn->setText("关闭串口");
|
||
// ui->NewOpenComButton->setText("关闭串口");
|
||
// ui->NewRegularSentButton->setEnabled(true);
|
||
|
||
// // 提示成功
|
||
// QString successMsg = tr("串口打开成功!\n串口: %1\n波特率: %2\n数据位: %3\n校验位: %4\n停止位: %5")
|
||
// .arg(currentSettings.name)
|
||
// .arg(currentSettings.baudRate)
|
||
// .arg(currentSettings.dataBits)
|
||
// .arg(currentSettings.parity)
|
||
// .arg(currentSettings.stopBits);
|
||
// CommonHelper::ShowMessageBoxInfo(successMsg);
|
||
// }
|
||
// else
|
||
// {
|
||
// // 获取详细错误信息
|
||
// QString errorString = m_serialPort->errorString();
|
||
// QSerialPort::SerialPortError error = m_serialPort->error();
|
||
|
||
// QString errorMsg;
|
||
// switch (error) {
|
||
// case QSerialPort::DeviceNotFoundError:
|
||
// errorMsg = tr("找不到指定的串口设备: %1").arg(currentSettings.name);
|
||
// break;
|
||
// case QSerialPort::PermissionError:
|
||
// errorMsg = tr("串口 %1 已被其他程序占用或权限不足").arg(currentSettings.name);
|
||
// break;
|
||
// case QSerialPort::OpenError:
|
||
// errorMsg = tr("无法打开串口 %1,可能已被占用").arg(currentSettings.name);
|
||
// break;
|
||
// case QSerialPort::NotOpenError:
|
||
// errorMsg = tr("串口未打开");
|
||
// break;
|
||
// default:
|
||
// errorMsg = tr("打开串口 %1 失败: %2").arg(currentSettings.name).arg(errorString);
|
||
// break;
|
||
// }
|
||
|
||
// CommonHelper::ShowMessageBoxError(errorMsg + tr("\n\n建议:\n1. 检查设备是否正确连接\n2. 确认串口未被其他程序占用\n3. 尝试刷新串口列表"));
|
||
|
||
// // 确保UI状态正确
|
||
// ui->connectBtn->setText("打开串口");
|
||
// ui->NewOpenComButton->setText("打开串口");
|
||
// ui->NewRegularSentButton->setEnabled(false);
|
||
// }
|
||
// }
|
||
void MainWindow::openSerialPort()
|
||
{
|
||
// 先关闭可能已经打开的串口
|
||
if (m_serialPort->isOpen())
|
||
{
|
||
m_serialPort->close();
|
||
QThread::msleep(100); // 等待串口完全关闭
|
||
}
|
||
|
||
// 更新串口配置
|
||
updateComSettings();
|
||
|
||
// 检查串口名称是否有效
|
||
if (currentSettings.name.isEmpty())
|
||
{
|
||
CommonHelper::ShowMessageBoxError(tr("串口名称无效,请重新选择串口!"));
|
||
return;
|
||
}
|
||
|
||
// 设置串口参数
|
||
m_serialPort->setPortName(currentSettings.name);
|
||
m_serialPort->setBaudRate(currentSettings.baudRate);
|
||
m_serialPort->setDataBits(currentSettings.dataBits);
|
||
m_serialPort->setParity(currentSettings.parity);
|
||
m_serialPort->setStopBits(currentSettings.stopBits);
|
||
m_serialPort->setFlowControl(QSerialPort::NoFlowControl);
|
||
|
||
// 尝试打开串口
|
||
if (m_serialPort->open(QIODevice::ReadWrite))
|
||
{
|
||
// 更新UI状态
|
||
ui->connectInfo->setPixmap(QPixmap(":/skin/image/info.png"));
|
||
ui->connectInfo->setScaledContents(true);
|
||
ui->connectBtn->setText("关闭串口");
|
||
ui->NewOpenComButton->setText("关闭串口");
|
||
// 删除这行,无论如何都不禁用定时发送按钮
|
||
// ui->NewRegularSentButton->setEnabled(true);
|
||
|
||
// 提示成功
|
||
QString successMsg = tr("串口打开成功!\n串口: %1\n波特率: %2\n数据位: %3\n校验位: %4\n停止位: %5")
|
||
.arg(currentSettings.name)
|
||
.arg(currentSettings.baudRate)
|
||
.arg(currentSettings.dataBits)
|
||
.arg(currentSettings.parity)
|
||
.arg(currentSettings.stopBits);
|
||
CommonHelper::ShowMessageBoxInfo(successMsg);
|
||
}
|
||
else
|
||
{
|
||
// 获取详细错误信息
|
||
QString errorString = m_serialPort->errorString();
|
||
QSerialPort::SerialPortError error = m_serialPort->error();
|
||
|
||
QString errorMsg;
|
||
switch (error)
|
||
{
|
||
case QSerialPort::DeviceNotFoundError:
|
||
errorMsg = tr("找不到指定的串口设备: %1").arg(currentSettings.name);
|
||
break;
|
||
case QSerialPort::PermissionError:
|
||
errorMsg = tr("串口 %1 已被其他程序占用或权限不足").arg(currentSettings.name);
|
||
break;
|
||
case QSerialPort::OpenError:
|
||
errorMsg = tr("无法打开串口 %1,可能已被占用").arg(currentSettings.name);
|
||
break;
|
||
case QSerialPort::NotOpenError:
|
||
errorMsg = tr("串口未打开");
|
||
break;
|
||
default:
|
||
errorMsg = tr("打开串口 %1 失败: %2").arg(currentSettings.name).arg(errorString);
|
||
break;
|
||
}
|
||
|
||
CommonHelper::ShowMessageBoxError(errorMsg + tr("\n\n建议:\n1. 检查设备是否正确连接\n2. 确认串口未被其他程序占用\n3. 尝试刷新串口列表"));
|
||
|
||
// 确保UI状态正确
|
||
ui->connectBtn->setText("打开串口");
|
||
ui->NewOpenComButton->setText("打开串口");
|
||
// 删除这行,避免禁用定时发送按钮
|
||
// ui->NewRegularSentButton->setEnabled(false);
|
||
}
|
||
}
|
||
|
||
void MainWindow::closeSerialPort()
|
||
{
|
||
if (m_serialPort->isOpen())
|
||
{
|
||
m_serialPort->close();
|
||
}
|
||
|
||
// 关闭串口时停止定时发送和累计时间
|
||
if (isRegularSending)
|
||
{
|
||
regularTimer->stop();
|
||
isRegularSending = false;
|
||
isPausedSending = false; // 重置暂停状态
|
||
ui->RegularlySentButton->setText("定时发送");
|
||
ui->NewRegularSentButton->setText("定时发送");
|
||
|
||
// 停止计时器
|
||
if (m_sendHistoryDialog && m_sendHistoryDialog->isTimingActive())
|
||
{
|
||
m_sendHistoryDialog->stopTimingCount();
|
||
m_sendHistoryDialog->setPauseState(false); // 重置发送历史对话框的暂停状态
|
||
}
|
||
}
|
||
}
|
||
|
||
// void MainWindow::writeData(const QString &data)
|
||
// {
|
||
// QByteArray arr;
|
||
// if (ui->isHexCheckBox->isChecked())
|
||
// {
|
||
// arr = QString2Hex(data);
|
||
// m_serialPort->write(arr);
|
||
|
||
// // 如果没有发送数据,在已发送编辑框就什么也不显示
|
||
// if (!data.isEmpty())
|
||
// {
|
||
// ui->sendTextEdit->append(data.toUpper());
|
||
// // 记录发送的日志
|
||
// if (m_logRecord->isLogging()) {
|
||
// m_logRecord->logSend(data.toUpper());
|
||
// }
|
||
|
||
// // 添加到发送历史记录
|
||
// showSendHistoryDialog();
|
||
// if (m_sendHistoryDialog) {
|
||
// m_sendHistoryDialog->addSendRecord(data.toUpper(), true);
|
||
// }
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// arr = data.toLatin1();
|
||
// m_serialPort->write(arr);
|
||
// // 如果没有发送数据,在已发送编辑框就什么也不显示
|
||
// if (!data.isEmpty())
|
||
// {
|
||
// ui->sendTextEdit->append(data);
|
||
// // 记录发送的日志
|
||
// if (m_logRecord->isLogging()) {
|
||
// m_logRecord->logSend(data);
|
||
// }
|
||
|
||
// // 添加到发送历史记录
|
||
// showSendHistoryDialog();
|
||
// if (m_sendHistoryDialog) {
|
||
// m_sendHistoryDialog->addSendRecord(data, false);
|
||
// }
|
||
// }
|
||
// }
|
||
// // 已发送计数
|
||
// sendCount += arr.size();
|
||
// ui->sendCountLabel->setNum(sendCount);
|
||
|
||
// // 当前文本50行时清除历史
|
||
// if ( 50 == ui->sendTextEdit->document()->lineCount())
|
||
// {
|
||
// // 读一行删一行
|
||
// QTextCursor txtcur= ui->sendTextEdit->textCursor();
|
||
// txtcur.setPosition(0);
|
||
// txtcur.movePosition(QTextCursor::EndOfLine,QTextCursor::KeepAnchor);
|
||
// QString qstr= txtcur.selectedText();
|
||
// txtcur.movePosition(QTextCursor::Down,QTextCursor::KeepAnchor);
|
||
// txtcur.movePosition(QTextCursor::StartOfLine,QTextCursor::KeepAnchor);
|
||
// txtcur.removeSelectedText();
|
||
// }
|
||
// }
|
||
|
||
// 在 writeData 方法中修改历史记录添加逻辑
|
||
void MainWindow::writeData(const QString& data)
|
||
{
|
||
QByteArray arr;
|
||
if (ui->isHexCheckBox->isChecked())
|
||
{
|
||
arr = QString2Hex(data);
|
||
m_serialPort->write(arr);
|
||
|
||
// 如果没有发送数据,在已发送编辑框就什么也不显示
|
||
if (!data.isEmpty())
|
||
{
|
||
ui->sendTextEdit->append(data.toUpper());
|
||
// 记录发送的日志
|
||
if (m_logRecord->isLogging())
|
||
{
|
||
m_logRecord->logSend(data.toUpper());
|
||
}
|
||
|
||
// 添加到发送历史记录 - 使用 true 表示HEX格式
|
||
showSendHistoryDialog();
|
||
if (m_sendHistoryDialog)
|
||
{
|
||
m_sendHistoryDialog->addSendRecord(data.toUpper(), true);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
arr = data.toLatin1();
|
||
m_serialPort->write(arr);
|
||
// 如果没有发送数据,在已发送编辑框就什么也不显示
|
||
if (!data.isEmpty())
|
||
{
|
||
ui->sendTextEdit->append(data);
|
||
// 记录发送的日志
|
||
if (m_logRecord->isLogging())
|
||
{
|
||
m_logRecord->logSend(data);
|
||
}
|
||
|
||
// 添加到发送历史记录 - 使用 false 表示ASCII格式
|
||
showSendHistoryDialog();
|
||
if (m_sendHistoryDialog)
|
||
{
|
||
m_sendHistoryDialog->addSendRecord(data, false);
|
||
}
|
||
}
|
||
}
|
||
// 已发送计数
|
||
sendCount += arr.size();
|
||
ui->sendCountLabel->setNum(sendCount);
|
||
|
||
// 当前文本50行时清除历史
|
||
if (50 == ui->sendTextEdit->document()->lineCount())
|
||
{
|
||
// 读一行删一行
|
||
QTextCursor txtcur = ui->sendTextEdit->textCursor();
|
||
txtcur.setPosition(0);
|
||
txtcur.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor);
|
||
QString qstr = txtcur.selectedText();
|
||
txtcur.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor);
|
||
txtcur.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor);
|
||
txtcur.removeSelectedText();
|
||
}
|
||
}
|
||
|
||
void MainWindow::readData()
|
||
{
|
||
// 读取串口缓冲区的所有数据给临时变量data
|
||
QByteArray data = m_serialPort->readAll();
|
||
|
||
QString str = ShowHex(data);
|
||
|
||
// 接收计数
|
||
receiveCount += data.count();
|
||
ui->receiveCountLabel->setNum(receiveCount);
|
||
|
||
// 将串口 读 的数据显示在 接收 数据文本框
|
||
if (!data.isEmpty())
|
||
{
|
||
ui->receiveTextEdit->append(str.toUpper());
|
||
|
||
// 记录接收的日志
|
||
if (m_logRecord->isLogging())
|
||
{
|
||
m_logRecord->logReceive(str.toUpper());
|
||
}
|
||
}
|
||
|
||
// 当前文本50行时清除历史
|
||
if (50 == ui->receiveTextEdit->document()->lineCount())
|
||
{
|
||
// 读一行删一行
|
||
QTextCursor txtcur = ui->receiveTextEdit->textCursor();
|
||
txtcur.setPosition(0);
|
||
txtcur.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor);
|
||
QString qstr = txtcur.selectedText();
|
||
txtcur.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor);
|
||
txtcur.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor);
|
||
txtcur.removeSelectedText();
|
||
}
|
||
}
|
||
|
||
void MainWindow::sendDataSlot()
|
||
{
|
||
ui->stackedWidget->setCurrentIndex(1);
|
||
|
||
// 机器型号
|
||
ui->modelNumLabel->setText(ui->modelNumLineEdit->text());
|
||
if (ui->modelNumLineEdit->text().isEmpty())
|
||
{
|
||
ui->modelNumLabel->setText("无型号");
|
||
}
|
||
// 生成按钮
|
||
createButtons();
|
||
// 读串口数据
|
||
readData();
|
||
}
|
||
|
||
void MainWindow::backSlot()
|
||
{
|
||
// 返回到上一页
|
||
ui->stackedWidget->setCurrentIndex(0);
|
||
ui->tabWidget->clear();
|
||
// 清除界面上的按钮
|
||
clearButtons();
|
||
}
|
||
|
||
void MainWindow::addItemSlot()
|
||
{
|
||
ui->removeItemButton->setEnabled(true);
|
||
ui->clearAllBtn->setEnabled(true);
|
||
|
||
// 获取表单行数
|
||
int rowCount = ui->tableWidget->rowCount();
|
||
// 插入新行
|
||
ui->tableWidget->insertRow(rowCount);
|
||
|
||
// 创建COLUMN_MAX列的空项目
|
||
for (int col = 0; col < COLUMN_MAX; ++col)
|
||
{
|
||
QTableWidgetItem* item = new QTableWidgetItem();
|
||
if (col == COLUMN_VALID) // 有效列
|
||
{
|
||
item->setCheckState(Qt::Checked);
|
||
item->setFlags(item->flags() & ~Qt::ItemIsEditable);
|
||
}
|
||
ui->tableWidget->setItem(rowCount, col, item);
|
||
}
|
||
|
||
// 添加发送按钮
|
||
QPushButton* sendButton = new QPushButton("发送");
|
||
sendButton->setProperty("row", rowCount);
|
||
connect(sendButton, SIGNAL(clicked()), this, SLOT(onSendButtonClicked()));
|
||
ui->tableWidget->setCellWidget(rowCount, COLUMN_SENDBUTTON, sendButton);
|
||
|
||
update();
|
||
ui->tableWidget->verticalScrollBar()->setValue(ui->tableWidget->verticalScrollBar()->maximum());
|
||
}
|
||
|
||
void MainWindow::removeItemSlot()
|
||
{
|
||
// 判断是否选择了一行
|
||
if (ui->tableWidget->currentItem() && ui->tableWidget->currentItem()->isSelected())
|
||
{
|
||
// 调用自定义消息提示框
|
||
int result = CommonHelper::ShowMessageBoxQuesion("是否删除当前已选中项?");
|
||
if (result == 1)
|
||
{
|
||
// 将对应的表格清除
|
||
QModelIndexList indexList = ui->tableWidget->selectionModel()->selectedIndexes();
|
||
while (!indexList.isEmpty())
|
||
{
|
||
QModelIndex index = indexList.first();
|
||
ui->tableWidget->model()->removeRow(index.row());
|
||
indexList = ui->tableWidget->selectionModel()->selectedIndexes();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
return;
|
||
}
|
||
}
|
||
// 如果一行都没有选中则提示
|
||
else
|
||
{
|
||
CommonHelper::ShowMessageBoxError("请选择需要删除的行!");
|
||
}
|
||
|
||
if (0 == ui->tableWidget->rowCount())
|
||
{
|
||
ui->removeItemButton->setEnabled(false);
|
||
ui->clearAllBtn->setEnabled(false);
|
||
}
|
||
else
|
||
{
|
||
ui->removeItemButton->setEnabled(true);
|
||
ui->clearAllBtn->setEnabled(true);
|
||
}
|
||
}
|
||
|
||
void MainWindow::clearAllSlot()
|
||
{
|
||
// 调用自定义消息提示框
|
||
int result = CommonHelper::ShowMessageBoxQuesion("是否清空全部数据?");
|
||
if (result == 1)
|
||
{
|
||
// 先将表格清除
|
||
ui->tableWidget->setRowCount(0);
|
||
// 再循环删除列表中的按钮对象
|
||
clearButtons();
|
||
}
|
||
else
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (0 == ui->tableWidget->rowCount())
|
||
{
|
||
ui->removeItemButton->setEnabled(false);
|
||
ui->clearAllBtn->setEnabled(false);
|
||
}
|
||
else
|
||
{
|
||
ui->removeItemButton->setEnabled(true);
|
||
ui->clearAllBtn->setEnabled(true);
|
||
}
|
||
}
|
||
|
||
void MainWindow::loadFileSlot()
|
||
{
|
||
QFileDialog* fileDialog = new QFileDialog(this);
|
||
fileDialog->setWindowTitle(tr("打开文件"));
|
||
fileDialog->setDirectory("../config");
|
||
|
||
QStringList filters;
|
||
filters << "配置文件(*.ini *.xlsx)"
|
||
<< "INI配置文件(*.ini)"
|
||
<< "XLSX文件(*.xlsx)"
|
||
<< "所有文件(*)";
|
||
fileDialog->setNameFilters(filters);
|
||
|
||
if (fileDialog->exec() == QDialog::Accepted)
|
||
{
|
||
QString loadFilePath = fileDialog->selectedFiles()[0];
|
||
// 先将表格清除
|
||
ui->tableWidget->setRowCount(0);
|
||
|
||
Document* doc = new Document(loadFilePath);
|
||
CellRange cellRange = doc->dimension();
|
||
Worksheet* sheet = dynamic_cast<Worksheet*>(doc->workbook()->sheet(0));
|
||
m_sheetName = sheet->sheetName();
|
||
if (sheet != nullptr)
|
||
{
|
||
// 根据信息初始化QTabelWidget
|
||
int row = cellRange.rowCount();
|
||
int column = cellRange.columnCount();
|
||
// ui->tableWidget->setColumnCount(cellRange.columnCount());
|
||
ui->tableWidget->setRowCount(cellRange.rowCount() - 1); // 去除第一行
|
||
ui->tableWidget->resizeColumnsToContents();
|
||
ui->tableWidget->setEditTriggers(QAbstractItemView::AllEditTriggers);
|
||
|
||
for (int i = 2; i <= cellRange.lastRow(); i++)
|
||
{
|
||
bool hasValidCommand = false;
|
||
for (int j = 1; j <= cellRange.lastColumn(); j++)
|
||
{
|
||
QTableWidgetItem* item = new QTableWidgetItem();
|
||
item->setTextAlignment(Qt::AlignVCenter | Qt::AlignCenter);
|
||
QString value = sheet->read(i, j).toString();
|
||
item->setText(value);
|
||
ui->tableWidget->setItem(i - 2, j - 1, item);
|
||
if (!value.isEmpty())
|
||
{
|
||
hasValidCommand = true;
|
||
}
|
||
// qDebug("%d,%d:%s", i, j, sheet->read(i,j).toString().toStdString().c_str());
|
||
}
|
||
|
||
// 第22列:有效性列 - 根据是否有设备指令判断
|
||
QTableWidgetItem* validItem = new QTableWidgetItem();
|
||
validItem->setFlags(validItem->flags() & ~Qt::ItemIsEditable);
|
||
validItem->setCheckState(hasValidCommand ? Qt::Checked : Qt::Unchecked);
|
||
ui->tableWidget->setItem(i, COLUMN_VALID, validItem);
|
||
|
||
// 第23列:添加发送按钮
|
||
QPushButton* sendButton = new QPushButton("发送");
|
||
sendButton->setProperty("row", i);
|
||
connect(sendButton, SIGNAL(clicked()), this, SLOT(onMultiDeviceSendButtonClicked()));
|
||
ui->tableWidget->setCellWidget(i, COLUMN_SENDBUTTON, sendButton);
|
||
}
|
||
|
||
// 提示加载完成
|
||
CommonHelper::ShowMessageBoxInfo(tr("CSV文件加载完成,共加载 %1 行数据").arg(row - 1));
|
||
}
|
||
}
|
||
|
||
if (0 == ui->tableWidget->rowCount())
|
||
{
|
||
ui->removeItemButton->setEnabled(false);
|
||
ui->clearAllBtn->setEnabled(false);
|
||
}
|
||
else
|
||
{
|
||
ui->removeItemButton->setEnabled(true);
|
||
ui->clearAllBtn->setEnabled(true);
|
||
}
|
||
}
|
||
|
||
//void MainWindow::loadFileSlot()
|
||
//{
|
||
// QFileDialog *fileDialog = new QFileDialog(this);
|
||
// fileDialog->setWindowTitle(tr("打开文件"));
|
||
// fileDialog->setDirectory("./");
|
||
|
||
// QStringList filters;
|
||
// filters << "配置文件(*.ini *.csv)"
|
||
// << "INI配置文件(*.ini)"
|
||
// << "CSV文件(*.csv)"
|
||
// << "所有文件(*)";
|
||
// fileDialog->setNameFilters(filters);
|
||
|
||
// if (fileDialog->exec() == QDialog::Accepted)
|
||
// {
|
||
// QString loadFilePath = fileDialog->selectedFiles()[0];
|
||
// // 先将表格清除
|
||
// ui->tableWidget->setRowCount(0);
|
||
|
||
// // 创建进度对话框
|
||
// QProgressDialog progress(tr("正在F..."), tr("取消"), 0, 100, this);
|
||
// progress.setWindowTitle(tr("请稍候"));
|
||
// progress.setWindowModality(Qt::WindowModal);
|
||
// progress.setMinimumDuration(0); // 立即显示
|
||
// progress.setValue(10);
|
||
// qApp->processEvents(); // 确保对话框显示
|
||
|
||
// // 获取文件信息
|
||
// QFileInfo fileInfo(loadFilePath);
|
||
// qint64 fileSize = fileInfo.size();
|
||
|
||
// // 更新进度对话框文本,显示文件信息
|
||
// progress.setLabelText(tr("正在读取文件: %1\n大小: %2 KB")
|
||
// .arg(fileInfo.fileName())
|
||
// .arg(fileSize / 1024.0, 0, 'f', 2));
|
||
// progress.setValue(15);
|
||
// qApp->processEvents();
|
||
|
||
// if (loadFilePath.endsWith(".csv", Qt::CaseInsensitive))
|
||
// {
|
||
// // 处理CSV文件
|
||
// QFile file(loadFilePath);
|
||
// if (!file.open(QIODevice::ReadOnly| QIODevice::Text))
|
||
// {
|
||
// progress.close();
|
||
// CommonHelper::ShowMessageBoxError(tr("无法打开CSV文件!"));
|
||
// return;
|
||
// }
|
||
|
||
// QTextStream in(&file);
|
||
// int row = 0;
|
||
// int totalLines = 0;
|
||
|
||
// // 设置文件编码
|
||
// #if defined(Q_OS_WIN)
|
||
// #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||
// in.setCodec("GBK");
|
||
// #else
|
||
// in.setEncoding(QStringConverter::System);
|
||
// #endif
|
||
// #else
|
||
// #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||
// in.setCodec("UTF-8");
|
||
// #else
|
||
// in.setEncoding(QStringConverter::Utf8);
|
||
// #endif
|
||
// #endif
|
||
|
||
// // 先计算总行数用于进度显示
|
||
// QString fileContent = in.readAll();
|
||
// totalLines = fileContent.count('\n') + 1;
|
||
// in.seek(0); // 重置文件指针
|
||
|
||
// progress.setMaximum(totalLines);
|
||
// progress.setValue(20);
|
||
// progress.setLabelText(tr("正在读取文件: %1\n行数统计完成,共 %2 行")
|
||
// .arg(fileInfo.fileName())
|
||
// .arg(totalLines));
|
||
// qApp->processEvents();
|
||
|
||
// // 强制跳过第一行(标题行),无论文件是否为空
|
||
// if (!in.atEnd()) {
|
||
// QString header = in.readLine();
|
||
// qDebug() << "已成功跳过CSV标题行: [" << header << "]";
|
||
// progress.setValue(25);
|
||
// qApp->processEvents();
|
||
// } else {
|
||
// qDebug() << "CSV文件为空或只有标题行";
|
||
// file.close();
|
||
// progress.close();
|
||
// CommonHelper::ShowMessageBoxError(tr("CSV文件为空或格式不正确!"));
|
||
// return;
|
||
// }
|
||
|
||
// // 读取每一行数据
|
||
// while (!in.atEnd())
|
||
// {
|
||
// QString line = in.readLine().trimmed();
|
||
// if (line.isEmpty()) continue;
|
||
|
||
// QStringList fields;
|
||
|
||
// // 解析CSV行,支持引号中的逗号
|
||
// bool inQuote = false;
|
||
// QString field;
|
||
// int num = line.length();
|
||
// for (int i = 0; i < num; ++i) {
|
||
// QChar c = line.at(i);
|
||
|
||
// if (c == "'") {
|
||
// inQuote = !inQuote;
|
||
// } else if (c == ',' && !inQuote) {
|
||
// fields.append(field.trimmed());
|
||
// field.clear();
|
||
// } else {
|
||
// field.append(c);
|
||
// }
|
||
// }
|
||
// fields.append(field.trimmed());
|
||
|
||
// // 确保有足够的字段数 - CSV实际有13列
|
||
// while (fields.size() < 2) {
|
||
// fields.append("");
|
||
// }
|
||
|
||
// // 插入新行
|
||
// ui->tableWidget->insertRow(row);
|
||
|
||
// // 创建23列的表格项,全部初始化
|
||
// for (int col = 0; col < COLUMN_MAX; ++col) {
|
||
// QTableWidgetItem *item = new QTableWidgetItem();
|
||
// if (col == COLUMN_VALID) { // 有效列
|
||
// item->setCheckState(Qt::Checked);
|
||
// item->setFlags(item->flags() & ~Qt::ItemIsEditable);
|
||
// }
|
||
// ui->tableWidget->setItem(row, col, item);
|
||
// }
|
||
|
||
// // 填充CSV数据到表格 - 修正列索引映射
|
||
// // CSV格式:0=序号, 1=时间轴, 2-13=12列设备数据
|
||
|
||
// // 第0列:序号 (CSV第0列)
|
||
// if (fields.size() > 0) {
|
||
// ui->tableWidget->item(row, 0)->setText(fields[0]);
|
||
// }
|
||
|
||
// // 第1列:时间轴,转换为毫秒 (CSV第1列)
|
||
// if (fields.size() > 1) {
|
||
// QString timeStr = fields[1];
|
||
// int timeInSeconds = timeStr.toInt();
|
||
// ui->tableWidget->item(row, 1)->setText(QString::number(timeInSeconds));
|
||
// }
|
||
|
||
// // 第2-16列:14列设备数据 (CSV第2-16列)
|
||
// for (int col = 2; col < COLUMN_VALID; ++col) {
|
||
// if (col < ui->tableWidget->columnCount() && col < fields.size()) {
|
||
// ui->tableWidget->item(row, col)->setText(fields[col]);
|
||
// } else if (col < ui->tableWidget->columnCount()) {
|
||
// ui->tableWidget->item(row, col)->setText(""); // 超出原CSV列数的部分设置为空
|
||
// }
|
||
// }
|
||
|
||
// // 第22列:有效性列 - 根据是否有设备指令判断
|
||
// QTableWidgetItem *validItem = new QTableWidgetItem();
|
||
// validItem->setFlags(validItem->flags() & ~Qt::ItemIsEditable);
|
||
// ui->tableWidget->setItem(row, COLUMN_VALID, validItem);
|
||
|
||
// // 检查是否有任何设备有指令或协议
|
||
// bool hasValidCommand = false;
|
||
// // 检查设备1-4的指令和协议列(每个设备占3列:指令、协议、通讯)
|
||
// // 设备1: 列2,3,4 设备2: 列5,6,7 设备3: 列8,9,10 设备4: 列11,12,13
|
||
// for (int devStart = 2; devStart < COLUMN_VALID; devStart += 3) {
|
||
// // 检查指令列(devStart)和协议列(devStart+1)
|
||
// if ((devStart < fields.size() && !fields[devStart].isEmpty()) ||
|
||
// (devStart + 1 < fields.size() && !fields[devStart + 1].isEmpty())) {
|
||
// hasValidCommand = true;
|
||
// break;
|
||
// }
|
||
// }
|
||
|
||
// ui->tableWidget->item(row, COLUMN_VALID)->setCheckState(hasValidCommand ? Qt::Checked : Qt::Unchecked);
|
||
|
||
// // 第18列:添加发送按钮
|
||
// QPushButton *sendButton = new QPushButton("发送");
|
||
// sendButton->setProperty("row", row);
|
||
// connect(sendButton, SIGNAL(clicked()), this, SLOT(onMultiDeviceSendButtonClicked()));
|
||
// ui->tableWidget->setCellWidget(row, COLUMN_SENDBUTTON, sendButton);
|
||
|
||
// row++;
|
||
|
||
// // 更新进度条
|
||
// int currentProgress = 25 + (row * 70 / totalLines);
|
||
// if (currentProgress > 95) currentProgress = 95;
|
||
// progress.setValue(currentProgress);
|
||
|
||
// // 每处理10行更新一次提示信息,避免频繁更新导致界面卡顿
|
||
// if (row % 10 == 0) {
|
||
// progress.setLabelText(tr("正在读取文件: %1\n已处理 %2/%3 行")
|
||
// .arg(fileInfo.fileName())
|
||
// .arg(row)
|
||
// .arg(totalLines - 1)); // 减1是因为跳过了标题行
|
||
// qApp->processEvents();
|
||
// }
|
||
|
||
// if (progress.wasCanceled()) {
|
||
// // 用户取消了操作,回滚已加载的内容
|
||
// ui->tableWidget->setRowCount(0);
|
||
// file.close();
|
||
// CommonHelper::ShowMessageBoxInfo(tr("文件加载已取消"));
|
||
// return;
|
||
// }
|
||
// }
|
||
|
||
// file.close();
|
||
|
||
// // 完成进度
|
||
// progress.setValue(100);
|
||
// progress.setLabelText(tr("文件加载完成: %1\n共处理 %2 行数据")
|
||
// .arg(fileInfo.fileName())
|
||
// .arg(row));
|
||
// qApp->processEvents();
|
||
// QThread::msleep(500); // 显示完成状态一小段时间
|
||
|
||
// // 提示加载完成
|
||
// CommonHelper::ShowMessageBoxInfo(tr("CSV文件加载完成,共加载 %1 行数据").arg(row));
|
||
// }
|
||
// else
|
||
// {
|
||
// // INI文件处理
|
||
// progress.setValue(30);
|
||
// progress.setLabelText(tr("正在读取INI配置文件: %1").arg(fileInfo.fileName()));
|
||
// qApp->processEvents();
|
||
|
||
// QSettings *loadSettings = nullptr;
|
||
// loadSettings = new QSettings(loadFilePath, QSettings::IniFormat);
|
||
|
||
// // 设置本地编码 - Qt 6中不再需要setIniCodec
|
||
// #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||
// // 使用Qt 5的方式
|
||
// #if defined(Q_OS_WIN)
|
||
// loadSettings->setIniCodec("GBK");
|
||
// #else
|
||
// loadSettings->setIniCodec("UTF-8");
|
||
// #endif
|
||
// #endif
|
||
|
||
// progress.setValue(40);
|
||
// qApp->processEvents();
|
||
|
||
// // 读按钮数据
|
||
// loadSettings->beginGroup("ButtonData");
|
||
// int nIndex = 0;
|
||
// int keyCount = 0;
|
||
|
||
// // 先获取键值数量,用于进度计算
|
||
// QStringList allKeys = loadSettings->childKeys();
|
||
// keyCount = allKeys.size();
|
||
// progress.setLabelText(tr("正在读取INI配置文件: %1\n共有 %2 个按钮配置")
|
||
// .arg(fileInfo.fileName())
|
||
// .arg(keyCount));
|
||
// qApp->processEvents();
|
||
|
||
// while (true)
|
||
// {
|
||
// // 没有找到key-value,就跳出循环
|
||
// if (loadSettings->value(QString("%1").arg(nIndex)).isNull())
|
||
// {
|
||
// break;
|
||
// }
|
||
|
||
// // 更新进度
|
||
// int currentProgress = 40 + (nIndex * 50 / (keyCount > 0 ? keyCount : 1));
|
||
// if (currentProgress > 90) currentProgress = 90;
|
||
// progress.setValue(currentProgress);
|
||
|
||
// // 每处理5个配置项更新一次提示
|
||
// if (nIndex % 5 == 0) {
|
||
// progress.setLabelText(tr("正在读取INI配置: %1\n已处理 %2/%3 项")
|
||
// .arg(fileInfo.fileName())
|
||
// .arg(nIndex)
|
||
// .arg(keyCount));
|
||
// qApp->processEvents();
|
||
// }
|
||
|
||
// if (progress.wasCanceled()) {
|
||
// delete loadSettings;
|
||
// ui->tableWidget->setRowCount(0);
|
||
// CommonHelper::ShowMessageBoxInfo(tr("文件加载已取消"));
|
||
// return;
|
||
// }
|
||
|
||
// // 每循环一次就插入新一行
|
||
// ui->tableWidget->insertRow(nIndex);
|
||
|
||
// // 用于保存取出的临时数据字符串列表
|
||
// QStringList tempStrList = loadSettings->value(QString("%1").arg(nIndex)).toStringList();
|
||
// QString tempStr = tempStrList[0];
|
||
|
||
// for (int i = 1; i < tempStrList.size(); i++)
|
||
// {
|
||
// tempStr += ",";
|
||
// tempStr += tempStrList[i];
|
||
// }
|
||
|
||
// // 修改使用 QRegularExpression 而非 QRegExp
|
||
// QStringList buttonInfoList = tempStr.split(QRegularExpression("[|]"));
|
||
|
||
// // 按照新格式解析:时间|按钮分类|按钮名称|鼠标按下命令|鼠标松开命令|是否有效
|
||
// QString buttonTimeStr = buttonInfoList[0];
|
||
// QString buttonGroupStr = buttonInfoList[1];
|
||
// QString buttonNameStr = buttonInfoList[2];
|
||
// QString mouseDownStr = buttonInfoList[3];
|
||
// QString mouseUpStr = buttonInfoList[4];
|
||
// QVariant buttonAvailStr = buttonInfoList[5];
|
||
|
||
// QTableWidgetItem *buttonTimeItem = new QTableWidgetItem;
|
||
// QTableWidgetItem *buttonGroupItem = new QTableWidgetItem;
|
||
// QTableWidgetItem *buttonNameItem = new QTableWidgetItem;
|
||
// QTableWidgetItem *mouseDownItem = new QTableWidgetItem;
|
||
// QTableWidgetItem *mouseUpItem = new QTableWidgetItem;
|
||
// QTableWidgetItem *buttonAvailItem = new QTableWidgetItem;
|
||
// buttonAvailItem->setFlags(buttonAvailItem->flags() & ~Qt::ItemIsEditable);
|
||
|
||
// ui->tableWidget->setItem(nIndex, 0, buttonTimeItem);
|
||
// ui->tableWidget->setItem(nIndex, 1, buttonGroupItem);
|
||
// ui->tableWidget->setItem(nIndex, 2, buttonNameItem);
|
||
// ui->tableWidget->setItem(nIndex, 3, mouseDownItem);
|
||
// ui->tableWidget->setItem(nIndex, 4, mouseUpItem);
|
||
// ui->tableWidget->setItem(nIndex, 5, buttonAvailItem);
|
||
|
||
// // 添加发送按钮
|
||
// QPushButton *sendButton = new QPushButton("发送");
|
||
// sendButton->setProperty("row", nIndex); // 存储按钮所在的行号
|
||
// connect(sendButton, SIGNAL(clicked()), this, SLOT(onSendButtonClicked()));
|
||
// ui->tableWidget->setCellWidget(nIndex, 6, sendButton);
|
||
|
||
// buttonTimeItem->setText(buttonTimeStr);
|
||
// buttonGroupItem->setText(buttonGroupStr);
|
||
// buttonNameItem->setText(buttonNameStr);
|
||
// mouseDownItem->setText(mouseDownStr);
|
||
// mouseUpItem->setText(mouseUpStr);
|
||
|
||
// switch (buttonAvailStr.toBool())
|
||
// {
|
||
// case 0:
|
||
// buttonAvailItem->setCheckState(Qt::Unchecked);
|
||
// break;
|
||
// case 1:
|
||
// buttonAvailItem->setCheckState(Qt::Checked);
|
||
// break;
|
||
// }
|
||
// nIndex++;
|
||
// }
|
||
// loadSettings->endGroup();
|
||
|
||
// progress.setValue(92);
|
||
// progress.setLabelText(tr("正在读取串口配置..."));
|
||
// qApp->processEvents();
|
||
|
||
// // 读串口配置数据
|
||
// loadSettings->beginGroup("comm");
|
||
// ui->baudRateComboBox->setCurrentIndex(loadSettings->value("BaudRate").toInt());
|
||
// ui->parityComboBox->setCurrentIndex(loadSettings->value("Parity").toInt());
|
||
// ui->dataBitsComboBox->setCurrentIndex(loadSettings->value("Bytesize").toInt());
|
||
// ui->stopBitsComboBox->setCurrentIndex(loadSettings->value("StopBits").toInt());
|
||
// bool isHex = loadSettings->value("SendByHex").toBool();
|
||
// ui->isHexCheckBox->setChecked(isHex);
|
||
// ui->modelNumLineEdit->setText(loadSettings->value("Name").toString());
|
||
// loadSettings->endGroup();
|
||
|
||
// delete loadSettings;
|
||
|
||
// progress.setValue(100);
|
||
// progress.setLabelText(tr("文件加载完成: %1\n共加载 %2 项配置")
|
||
// .arg(fileInfo.fileName())
|
||
// .arg(nIndex));
|
||
// qApp->processEvents();
|
||
// QThread::msleep(500); // 显示完成状态一小段时间
|
||
|
||
// // 提示加载完成
|
||
// CommonHelper::ShowMessageBoxInfo(tr("INI文件加载完成,共加载 %1 项配置").arg(nIndex));
|
||
// }
|
||
// }
|
||
|
||
// if (0 == ui->tableWidget->rowCount())
|
||
// {
|
||
// ui->removeItemButton->setEnabled(false);
|
||
// ui->clearAllBtn->setEnabled(false);
|
||
// }else {
|
||
// ui->removeItemButton->setEnabled(true);
|
||
// ui->clearAllBtn->setEnabled(true);
|
||
// }
|
||
//}
|
||
|
||
void MainWindow::saveFileSlot()
|
||
{
|
||
QString saveFilePath = QFileDialog::getSaveFileName(this,
|
||
tr("文件另存为"), "../config", tr("xlsx文件(*.xlsx);;INI配置文件(*.ini);;所有文件(*)"));
|
||
|
||
if (saveFilePath.isEmpty())
|
||
return;
|
||
QFile old_file(saveFilePath);
|
||
if (old_file.exists())
|
||
{
|
||
if (!old_file.remove())
|
||
{
|
||
return;
|
||
}
|
||
}
|
||
|
||
Document doc;
|
||
doc.addSheet(m_sheetName);
|
||
doc.selectSheet(m_sheetName);
|
||
|
||
if (saveFilePath.endsWith(".xlsx", Qt::CaseInsensitive))
|
||
{
|
||
|
||
int rowCount = ui->tableWidget->rowCount();
|
||
int columnCount = ui->tableWidget->columnCount();
|
||
|
||
// 写首行,从第一列开始
|
||
for (int i = 1; i <= m_headers.size(); i++)
|
||
{
|
||
// excel中起始行和列从1开始
|
||
doc.write(1, i, m_headers[i - 1]);
|
||
}
|
||
// 写数据
|
||
for (int i = 0; i < rowCount; i++)
|
||
{
|
||
for (int j = 0; j < COLUMN_VALID; j++)
|
||
{
|
||
QString itemStr = ui->tableWidget->item(i, j)->text();
|
||
doc.write(i + 2, j + 2, itemStr);
|
||
}
|
||
}
|
||
if (!doc.saveAs(saveFilePath))
|
||
{
|
||
CommonHelper::ShowMessageBoxError("文件保存失败!");
|
||
return;
|
||
}
|
||
doc.deleteLater();
|
||
}
|
||
else
|
||
{
|
||
// 原有的INI文件保存代码
|
||
QSettings* saveSettings = nullptr;
|
||
saveSettings = new QSettings(saveFilePath, QSettings::IniFormat);
|
||
|
||
// 设置本地编码 - Qt 6中不再需要setIniCodec
|
||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||
// 使用Qt 5的方式
|
||
#if defined(Q_OS_WIN)
|
||
saveSettings->setIniCodec("GBK");
|
||
#else
|
||
saveSettings->setIniCodec("UTF-8");
|
||
#endif
|
||
#endif
|
||
|
||
// 写按钮数据
|
||
saveSettings->beginGroup("ButtonData");
|
||
for (int nIndex = 0; nIndex < ui->tableWidget->rowCount(); nIndex++)
|
||
{
|
||
// // 表格中按钮名称没有填写,就跳出循环
|
||
// QString str = ui->tableWidget->item(nIndex, 0)->text();
|
||
// if (str.isEmpty())
|
||
// {
|
||
// break;
|
||
// }
|
||
QString buttonTimeStr = ui->tableWidget->item(nIndex, 0)->text();
|
||
QString buttonGroupStr = ui->tableWidget->item(nIndex, 1)->text();
|
||
QString buttonNameStr = ui->tableWidget->item(nIndex, 2)->text();
|
||
QString mouseDownStr = ui->tableWidget->item(nIndex, 3)->text();
|
||
QString mouseUpStr = ui->tableWidget->item(nIndex, 4)->text();
|
||
bool isAvail = ui->tableWidget->item(nIndex, 5)->checkState();
|
||
QString buttonAvailStr;
|
||
switch (isAvail)
|
||
{
|
||
case 0:
|
||
buttonAvailStr = "False";
|
||
break;
|
||
case 1:
|
||
buttonAvailStr = "True";
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
QString tempStr = buttonGroupStr + "|" + buttonNameStr + "|"
|
||
+ mouseDownStr + "|" + mouseUpStr + "|" + buttonAvailStr;
|
||
// 修改使用 QRegularExpression 而非 QRegExp
|
||
QStringList tempStrList = tempStr.split(QRegularExpression("[,]"));
|
||
saveSettings->setValue(QString("%1").arg(nIndex), tempStrList);
|
||
}
|
||
|
||
saveSettings->endGroup();
|
||
|
||
// 写串口配置数据
|
||
saveSettings->beginGroup("comm");
|
||
saveSettings->setValue("BaudRate", ui->baudRateComboBox->currentIndex());
|
||
saveSettings->setValue("Parity", ui->parityComboBox->currentIndex());
|
||
saveSettings->setValue("Bytesize", ui->dataBitsComboBox->currentIndex());
|
||
saveSettings->setValue("StopBits", ui->stopBitsComboBox->currentIndex());
|
||
saveSettings->setValue("SendByHex", QString::number(ui->isHexCheckBox->isChecked()));
|
||
saveSettings->setValue("Name", ui->modelNumLineEdit->text());
|
||
saveSettings->endGroup();
|
||
|
||
delete saveSettings;
|
||
}
|
||
}
|
||
|
||
void MainWindow::createButtons()
|
||
{
|
||
QStringList groupNameList; // 存放生成的按钮分组标签名字
|
||
// 分组名获取
|
||
for (int i = 0; i < ui->tableWidget->rowCount(); i++)
|
||
{
|
||
groupNameList << ui->tableWidget->item(i, 1)->text();
|
||
}
|
||
removeListSame(&groupNameList);
|
||
|
||
// 创建 分类的组
|
||
for (int i = 0; i < groupNameList.size(); i++)
|
||
{
|
||
// 层叠关系(父->子):buttonFrame(gridLayout)->scrollArea->scrollWidget(gLayout)->pButton
|
||
QFrame* buttonFrame = new QFrame(this);
|
||
QScrollArea* scrollArea = new QScrollArea(this);
|
||
|
||
QGridLayout* gridLayout = new QGridLayout(this);
|
||
gridLayout->addWidget(scrollArea);
|
||
gridLayout->setContentsMargins(0, 0, 0, 0); // 替换setMargin(0)
|
||
gridLayout->setSpacing(0);
|
||
buttonFrame->setLayout(gridLayout);
|
||
|
||
QGridLayout* gLayout = new QGridLayout(this);
|
||
gLayout->setContentsMargins(30, 12, 30, 12);
|
||
gLayout->setSpacing(20);
|
||
gLayout->setSizeConstraint(QGridLayout::SetFixedSize);
|
||
|
||
QWidget* scrollWidget = new QWidget(this);
|
||
scrollWidget->setLayout(gLayout);
|
||
|
||
scrollArea->setWidget(scrollWidget);
|
||
scrollArea->setWidgetResizable(true);
|
||
gLayoutList << gLayout;
|
||
|
||
ui->tabWidget->addTab(buttonFrame, groupNameList[i]);
|
||
}
|
||
|
||
//遍历Tab页
|
||
for (int i = 0; i < ui->tabWidget->count(); i++)
|
||
{
|
||
QString currentTabText = ui->tabWidget->tabText(i);
|
||
|
||
// 设置生成的 按钮 行、列
|
||
int row = 0, col = 0;
|
||
// 循环创建 按钮
|
||
for (int nIndex = 0; nIndex < ui->tableWidget->rowCount(); nIndex++)
|
||
{
|
||
QString buttonTypeStr = ui->tableWidget->item(nIndex, 1)->text();
|
||
// 核对Tab页名字是否和按钮所分类相同
|
||
if (currentTabText == buttonTypeStr)
|
||
{
|
||
// 修改这里,使用按钮名称(第3列,索引2)而不是分类名称
|
||
QPushButton* pButton = new QPushButton(
|
||
QString("%1").arg(ui->tableWidget->item(nIndex, 2)->text()));
|
||
//按钮尺寸
|
||
pButton->setMinimumHeight(26);
|
||
pButton->setMinimumWidth(120);
|
||
// 按钮是否已勾选有效 已勾选则显示 未勾选则不显示
|
||
if (ui->tableWidget->item(nIndex, 5)->checkState() == Qt::Checked)
|
||
{
|
||
int alpha = ui->centralWidget->width() / 156;
|
||
gLayoutList[i]->addWidget(pButton, (row++) / alpha, (col++) % alpha, 1, 1);
|
||
pButton->show();
|
||
}
|
||
// 插入控件列表
|
||
buttonList.insert(nIndex, pButton);
|
||
// 信号槽连接
|
||
connect(pButton, SIGNAL(pressed()), this, SLOT(mouseDownSlot()));
|
||
connect(pButton, SIGNAL(released()), this, SLOT(mouseUpSlot()));
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
}
|
||
|
||
void MainWindow::clearButtons()
|
||
{
|
||
QList< QPushButton* >::iterator iter;
|
||
for (iter = buttonList.begin(); iter != buttonList.end(); iter++)
|
||
{
|
||
delete *iter;
|
||
}
|
||
buttonList.clear();
|
||
|
||
QList< QGridLayout* >::iterator iter2;
|
||
for (iter2 = gLayoutList.begin(); iter2 != gLayoutList.end(); iter2++)
|
||
{
|
||
delete *iter2;
|
||
}
|
||
gLayoutList.clear();
|
||
}
|
||
|
||
void MainWindow::mouseDownSlot()
|
||
{
|
||
// 通过sender找出点击的button
|
||
QPushButton* tmpButton = reinterpret_cast<QPushButton*>(sender());
|
||
|
||
for (int i = 0; i < buttonList.size(); i++)
|
||
{
|
||
if (tmpButton == buttonList.at(i)
|
||
&& ui->tableWidget->item(i, 5)->checkState() == Qt::Checked)
|
||
{
|
||
pressStr = ui->tableWidget->item(i, 3)->text();
|
||
// 替换逗号
|
||
pressStr.replace(QString(","), QString(" "));
|
||
// 1.单点发送命令(点击一次)
|
||
writeData(pressStr);
|
||
// 2.长按发送命令(按住不放)
|
||
PressTimer->start(BUTTON_REPEAT_INTERVAL);
|
||
|
||
tmpButton = NULL;
|
||
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
void MainWindow::mouseUpSlot()
|
||
{
|
||
// 通过sender找出点击的button
|
||
QPushButton* tmpButton = reinterpret_cast<QPushButton*>(sender());
|
||
|
||
for (int i = 0; i < buttonList.size(); i++)
|
||
{
|
||
if (tmpButton == buttonList.at(i)
|
||
&& ui->tableWidget->item(i, 5)->checkState() == Qt::Checked)
|
||
{
|
||
// 按钮松开时 计时器停
|
||
PressTimer->stop();
|
||
|
||
QString str = ui->tableWidget->item(i, 4)->text();
|
||
// 替换逗号
|
||
str.replace(QString(","), QString(" "));
|
||
writeData(str);
|
||
tmpButton = NULL;
|
||
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
void MainWindow::sendTextAutoScrollSlot()
|
||
{
|
||
// 设置发送框垂直滚动条的值
|
||
ui->sendTextEdit->setVerticalScrollBar(new QScrollBar);
|
||
ui->sendTextEdit->verticalScrollBar()->setValue(ui->sendTextEdit->verticalScrollBar()->maximum());
|
||
}
|
||
|
||
void MainWindow::receiveTextAutoScrollSlot()
|
||
{
|
||
// 设置接收框垂直滚动条的值
|
||
ui->receiveTextEdit->setVerticalScrollBar(new QScrollBar);
|
||
ui->receiveTextEdit->verticalScrollBar()->setValue(ui->receiveTextEdit->verticalScrollBar()->maximum());
|
||
}
|
||
|
||
void MainWindow::on_clearSendButton_clicked()
|
||
{
|
||
// 调用自定义消息提示框
|
||
int result = CommonHelper::ShowMessageBoxQuesion("是否清空发送数据?");
|
||
if (result == 1)
|
||
{
|
||
ui->sendTextEdit->clear();
|
||
sendCount = 0;
|
||
ui->sendCountLabel->setNum(sendCount);
|
||
}
|
||
else
|
||
{
|
||
return;
|
||
}
|
||
}
|
||
|
||
void MainWindow::on_clearReceiveButton_clicked()
|
||
{
|
||
// 调用自定义消息提示框
|
||
int result = CommonHelper::ShowMessageBoxQuesion("是否清空接收数据?");
|
||
if (result == 1)
|
||
{
|
||
ui->receiveTextEdit->clear();
|
||
receiveCount = 0;
|
||
ui->receiveCountLabel->setNum(receiveCount);
|
||
}
|
||
else
|
||
{
|
||
return;
|
||
}
|
||
}
|
||
|
||
void MainWindow::on_styleComboBox_currentIndexChanged(int index)
|
||
{
|
||
switch (index)
|
||
{
|
||
case 0:
|
||
getCurrentDate();
|
||
break;
|
||
case 1:
|
||
styleStr = "green";
|
||
break;
|
||
case 2:
|
||
styleStr = "dark";
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
// 设置样式表
|
||
QFile file(QString(":/skin/stylesheet/%1.qss").arg(styleStr));
|
||
file.open(QFile::ReadOnly);
|
||
QString qss = QLatin1String(file.readAll());
|
||
qApp->setStyleSheet(qss);
|
||
}
|
||
|
||
void MainWindow::on_customSendButton_clicked()
|
||
{
|
||
if (! ui->customLineEdit->text().isEmpty())
|
||
{
|
||
QString customStr = ui->customLineEdit->text();
|
||
writeData(customStr);
|
||
|
||
// 已经在writeData中处理了历史记录的添加和显示
|
||
}
|
||
}
|
||
|
||
void MainWindow::on_customLineEdit_textChanged()
|
||
{
|
||
QRegularExpression regExp("^[A-Fa-f0-9\\s]+$"); // 匹配 0-9 A-F a-f 空格
|
||
bool match = regExp.match(ui->customLineEdit->text()).hasMatch();
|
||
if (!match && !ui->customLineEdit->text().isEmpty())
|
||
{
|
||
CommonHelper::ShowMessageBoxError(tr("请输入有效Hex字符组合\"0-9\",\"A-F\",\"a-f\",\" \"!\n每两个字符之间空一个空格。"));
|
||
}
|
||
}
|
||
|
||
void MainWindow::on_intervalLineEdit_textChanged()
|
||
{
|
||
QRegularExpression reg("^[0-9]+$");
|
||
ui->intervalLineEdit->setValidator(new QRegularExpressionValidator(reg, this));
|
||
}
|
||
|
||
void MainWindow::on_timerCheckBox_stateChanged(int state)
|
||
{
|
||
switch (state)
|
||
{
|
||
case 0: // Unchecked
|
||
if (timer->isActive())
|
||
{
|
||
timer->stop();
|
||
}
|
||
break;
|
||
case 2: // Checked
|
||
if (! ui->intervalLineEdit->text().isEmpty())
|
||
{
|
||
int interval = ui->intervalLineEdit->text().toInt();
|
||
timer->start(interval);
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
void MainWindow::timerUpdate()
|
||
{
|
||
on_customSendButton_clicked();
|
||
}
|
||
|
||
void MainWindow::on_checkResultBtn_clicked()
|
||
{
|
||
QRegularExpression regExp("^[A-Fa-f0-9\\s]+$"); // 匹配 0-9 A-F a-f 空格
|
||
bool match = regExp.match(ui->inputCommandTextEdit->toPlainText()).hasMatch();
|
||
if (!match && !ui->inputCommandTextEdit->toPlainText().isEmpty())
|
||
{
|
||
CommonHelper::ShowMessageBoxError(tr("请输入有效Hex字符组合\"0-9\",\"A-F\",\"a-f\",\" \"!\n每两个字符之间空一个空格。"));
|
||
}
|
||
|
||
QString inputCommandStr = ui->inputCommandTextEdit->toPlainText();
|
||
QByteArray inputCommandArr = QString2Hex(inputCommandStr);
|
||
if (ui->xorRadioButton->isChecked())
|
||
{
|
||
char checkHex = xorCheck(inputCommandArr);
|
||
QString str = QString("%1").arg(checkHex & 0xFF, 2, 16, QLatin1Char('0')).toUpper();
|
||
ui->checkResultLineEdit->setText(str);
|
||
}
|
||
else if (ui->sumRadioButton->isChecked())
|
||
{
|
||
char checkHex = sumCheck(inputCommandArr);
|
||
QString str = QString("%1").arg(checkHex & 0xFF, 2, 16, QLatin1Char('0')).toUpper();
|
||
ui->checkResultLineEdit->setText(str);
|
||
}
|
||
|
||
}
|
||
|
||
void MainWindow::on_clearInputCommandBtn_clicked()
|
||
{
|
||
ui->inputCommandTextEdit->clear();
|
||
}
|
||
|
||
void MainWindow::on_settingsCheckBox_stateChanged(int state)
|
||
{
|
||
switch (state)
|
||
{
|
||
case 0: // Unchecked
|
||
ui->settingsGroupBox->hide();
|
||
break;
|
||
case 2: // Checked
|
||
ui->settingsGroupBox->show();
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
void MainWindow::on_openFileButton_clicked()
|
||
{
|
||
QFileDialog* fileDialog = new QFileDialog(this);
|
||
fileDialog->setWindowTitle(tr("打开文件"));
|
||
fileDialog->setDirectory("./");
|
||
|
||
QStringList filters;
|
||
filters << "TXT文件(*.txt)"
|
||
<< "所有文件(*)";
|
||
fileDialog->setNameFilters(filters);
|
||
|
||
QStringList fileName;
|
||
if (fileDialog->exec() == QDialog::Accepted)
|
||
{
|
||
fileName = fileDialog->selectedFiles();
|
||
QString pathName = fileName.join(",");
|
||
ui->filePathLineEdit->setText(pathName);
|
||
|
||
}
|
||
}
|
||
|
||
void MainWindow::on_sendFileButton_clicked()
|
||
{
|
||
QString fileName = ui->filePathLineEdit->text();
|
||
|
||
if (fileName.isEmpty())
|
||
{
|
||
CommonHelper::ShowMessageBoxError(tr("请选择一个文件!"));
|
||
return;
|
||
}
|
||
|
||
QFileInfo* fileInfo = new QFileInfo(fileName);
|
||
int fileSize = fileInfo->size();
|
||
|
||
QFile file;
|
||
file.setFileName(fileName);
|
||
if (!file.open(QIODevice::ReadOnly))
|
||
{
|
||
// 文件打开失败
|
||
return;
|
||
}
|
||
|
||
QDataStream in(&file);
|
||
|
||
char* dataBuffer;
|
||
dataBuffer = new char[fileSize];
|
||
in.setVersion(QDataStream::Qt_5_6);
|
||
//读出文件到缓存
|
||
in.readRawData(dataBuffer, fileSize);
|
||
file.close();
|
||
|
||
if (!updateBuffer)
|
||
{
|
||
delete updateBuffer;
|
||
}
|
||
dataSize = fileSize;
|
||
updateBuffer = new char[dataSize];
|
||
|
||
int j = 0;
|
||
// 数据
|
||
for (int i = 0; i < fileSize; i++)
|
||
{
|
||
updateBuffer[j++] = dataBuffer[i];
|
||
}
|
||
|
||
delete dataBuffer;
|
||
|
||
bSendFile = true;
|
||
|
||
sendFile();
|
||
}
|
||
|
||
void MainWindow::sendFileTimerUpdate()
|
||
{
|
||
int packSize = 1; // 每次发128个字节
|
||
char* Temp;
|
||
Temp = new char[packSize];
|
||
|
||
if (m_lSendPoint * packSize < dataSize)
|
||
{
|
||
memcpy(Temp, updateBuffer + packSize * m_lSendPoint, packSize);
|
||
m_serialPort->write(Temp, packSize);
|
||
|
||
// 0QString str = QString(QLatin1String(Temp));
|
||
// ui->sendTextEdit->append(str);
|
||
}
|
||
// else
|
||
// {
|
||
// int itemt = dataSize - (m_lSendPoint - 1)*packSize;
|
||
// // 发送最后一条命令(当前数据长度不能被128整除的部分)
|
||
// memcpy(Temp, updateBuffer + 2 * (m_lSendPoint - 1), itemt);
|
||
// m_serialPort->write(Temp, itemt);
|
||
|
||
// sendFileTimer->stop();
|
||
// }
|
||
m_lSendPoint++;
|
||
|
||
if (m_lSendPoint * packSize == dataSize)
|
||
{
|
||
sendFileTimer->stop();
|
||
dataSize = 0;
|
||
}
|
||
|
||
delete Temp;
|
||
}
|
||
|
||
void MainWindow::PressTimerUpdate()
|
||
{
|
||
writeData(pressStr);
|
||
}
|
||
|
||
void MainWindow::connectCOMButtonSlot()
|
||
{
|
||
if ("打开串口" == ui->connectBtn->text())
|
||
{
|
||
openSerialPort();
|
||
|
||
// 同步新按钮状态
|
||
if ("关闭串口" == ui->connectBtn->text())
|
||
{
|
||
ui->NewRegularSentButton->setEnabled(true);
|
||
ui->NewOpenComButton->setText("关闭串口");
|
||
}
|
||
}
|
||
else if ("关闭串口" == ui->connectBtn->text())
|
||
{
|
||
ui->connectInfo->setPixmap(QPixmap(":/skin/image/error.png"));
|
||
ui->connectInfo->setScaledContents(true);
|
||
ui->connectBtn->setText("打开串口");
|
||
ui->NewOpenComButton->setText("打开串口");
|
||
|
||
// 停止定时发送并禁用相关按钮
|
||
if (isRegularSending)
|
||
{
|
||
regularTimer->stop();
|
||
isRegularSending = false;
|
||
ui->RegularlySentButton->setText("定时发送");
|
||
ui->NewRegularSentButton->setText("定时发送");
|
||
}
|
||
ui->NewRegularSentButton->setEnabled(false);
|
||
|
||
closeSerialPort();
|
||
}
|
||
}
|
||
|
||
// 实现主界面的打开串口按钮功能
|
||
// void MainWindow::on_NewOpenComButton_clicked()
|
||
// {
|
||
// if (ui->NewOpenComButton->text() == "打开串口")
|
||
// {
|
||
// // 检查是否选择了串口
|
||
// if (ui->NewComcomboBox->currentText().isEmpty()) {
|
||
// CommonHelper::ShowMessageBoxError(tr("请先选择串口!"));
|
||
// // 自动刷新串口列表
|
||
// updatePortsInComboBoxes();
|
||
// return;
|
||
// }
|
||
|
||
// // 调用统一的打开串口方法
|
||
// openSerialPort();
|
||
// }
|
||
// else // "关闭串口" 状态
|
||
// {
|
||
// closeSerialPort();
|
||
|
||
// // 更新UI状态
|
||
// ui->connectInfo->setPixmap(QPixmap(":/skin/image/error.png"));
|
||
// ui->connectInfo->setScaledContents(true);
|
||
// ui->connectBtn->setText("打开串口");
|
||
// ui->NewOpenComButton->setText("打开串口");
|
||
// // ui->NewRegularSentButton->setEnabled(false);
|
||
|
||
// CommonHelper::ShowMessageBoxInfo(tr("串口已关闭"));
|
||
// }
|
||
// }
|
||
void MainWindow::on_NewOpenComButton_clicked()
|
||
{
|
||
if (ui->NewOpenComButton->text() == "打开串口")
|
||
{
|
||
// 检查是否选择了串口
|
||
if (ui->NewComcomboBox->currentText().isEmpty())
|
||
{
|
||
CommonHelper::ShowMessageBoxError(tr("请先选择串口!"));
|
||
// 自动刷新串口列表
|
||
updatePortsInComboBoxes();
|
||
return;
|
||
}
|
||
|
||
// 调用统一的打开串口方法
|
||
openSerialPort();
|
||
}
|
||
else // "关闭串口" 状态
|
||
{
|
||
closeSerialPort();
|
||
|
||
// 更新UI状态
|
||
ui->connectInfo->setPixmap(QPixmap(":/skin/image/error.png"));
|
||
ui->connectInfo->setScaledContents(true);
|
||
ui->connectBtn->setText("打开串口");
|
||
ui->NewOpenComButton->setText("打开串口");
|
||
// 删除这行,避免禁用定时发送按钮
|
||
// ui->NewRegularSentButton->setEnabled(false);
|
||
|
||
CommonHelper::ShowMessageBoxInfo(tr("串口已关闭"));
|
||
}
|
||
}
|
||
|
||
void MainWindow::updatePortsInComboBoxes()
|
||
{
|
||
// 保存当前选中的串口
|
||
QString currentPort1 = ui->comComboBox->currentText();
|
||
QString currentPort2 = ui->NewComcomboBox->currentText();
|
||
|
||
// 清空串口列表
|
||
ui->comComboBox->clear();
|
||
ui->NewComcomboBox->clear();
|
||
|
||
// 获取系统中可用的串口
|
||
QList<QSerialPortInfo> ports = QSerialPortInfo::availablePorts();
|
||
|
||
// 填充串口选择框
|
||
bool foundPort1 = false, foundPort2 = false;
|
||
foreach (const QSerialPortInfo& info, ports)
|
||
{
|
||
QString portText = info.portName();
|
||
// 添加设备描述信息
|
||
if (!info.description().isEmpty() && info.description() != "n/a")
|
||
{
|
||
portText += " (" + info.description() + ")";
|
||
}
|
||
|
||
ui->comComboBox->addItem(portText, info.portName());
|
||
ui->NewComcomboBox->addItem(portText, info.portName());
|
||
|
||
// 检查是否是之前选中的串口
|
||
if (portText.contains(currentPort1.split("(").first().trimmed()))
|
||
{
|
||
ui->comComboBox->setCurrentIndex(ui->comComboBox->count() - 1);
|
||
foundPort1 = true;
|
||
}
|
||
if (portText.contains(currentPort2.split("(").first().trimmed()))
|
||
{
|
||
ui->NewComcomboBox->setCurrentIndex(ui->NewComcomboBox->count() - 1);
|
||
foundPort2 = true;
|
||
}
|
||
}
|
||
|
||
// 更新按钮状态
|
||
bool hasAvailablePorts = !ports.isEmpty();
|
||
ui->connectBtn->setEnabled(hasAvailablePorts);
|
||
ui->NewOpenComButton->setEnabled(hasAvailablePorts);
|
||
|
||
if (!hasAvailablePorts)
|
||
{
|
||
CommonHelper::ShowMessageBoxInfo(tr("未检测到可用的串口设备。\n\n请确认:\n1. 设备已正确连接\n2. 驱动程序已安装\n3. 设备未被其他程序占用"));
|
||
}
|
||
else
|
||
{
|
||
qDebug() << "发现" << ports.size() << "个可用串口";
|
||
}
|
||
|
||
// 如果之前选中的串口不存在了,给出提示
|
||
if (!currentPort1.isEmpty() && !foundPort1)
|
||
{
|
||
qDebug() << "之前选中的串口" << currentPort1 << "已断开";
|
||
}
|
||
if (!currentPort2.isEmpty() && !foundPort2)
|
||
{
|
||
qDebug() << "之前选中的串口" << currentPort2 << "已断开";
|
||
}
|
||
}
|
||
|
||
void MainWindow::showSendHistoryDialog()
|
||
{
|
||
// 如果对话框还没创建,则创建它
|
||
if (!m_sendHistoryDialog)
|
||
{
|
||
m_sendHistoryDialog = new SendHistoryDialog(this);
|
||
|
||
// 连接信号槽
|
||
connect(m_sendHistoryDialog, SIGNAL(sendCommand(QString)),
|
||
this, SLOT(writeData(QString)));
|
||
|
||
// 添加暂停/恢复定时发送的信号连接
|
||
connect(m_sendHistoryDialog, SIGNAL(pauseRegularSending(bool)),
|
||
this, SLOT(handlePauseRegularSending(bool)));
|
||
}
|
||
|
||
// 如果对话框尚未显示,则显示它
|
||
if (!m_sendHistoryDialog->isVisible())
|
||
{
|
||
m_sendHistoryDialog->show();
|
||
m_sendHistoryDialog->raise(); // 确保它在最前面
|
||
m_sendHistoryDialog->activateWindow(); // 让它获得焦点
|
||
}
|
||
}
|
||
|
||
// 处理暂停和恢复定时发送
|
||
void MainWindow::handlePauseRegularSending(bool pause)
|
||
{
|
||
if (isRegularSending)
|
||
{
|
||
if (pause && !isPausedSending)
|
||
{
|
||
// 暂停定时发送 - 停止定时器但不重置标志
|
||
regularTimer->stop();
|
||
isPausedSending = true;
|
||
|
||
// 暂停累计时间计时器 - 记录暂停时间点
|
||
if (m_sendHistoryDialog)
|
||
{
|
||
if (m_sendHistoryDialog->isTimingActive())
|
||
{
|
||
m_sendHistoryDialog->stopTimingCount();
|
||
}
|
||
m_sendHistoryDialog->setPauseState(true);
|
||
}
|
||
|
||
// 更新UI状态但保持isRegularSending标志
|
||
ui->RegularlySentButton->setText("恢复发送"); // 修改为"恢复发送"而非"定时发送(已暂停)"
|
||
ui->NewRegularSentButton->setText("恢复发送");
|
||
|
||
qDebug() << QString("定时发送已暂停,当前累计时间:%1秒").arg(elapsedSeconds);
|
||
}
|
||
else if (!pause && isPausedSending)
|
||
{
|
||
// 恢复定时发送 - 重新启动定时器
|
||
isPausedSending = false;
|
||
|
||
// 恢复累计时间计时器 - 从暂停点继续
|
||
if (m_sendHistoryDialog)
|
||
{
|
||
m_sendHistoryDialog->setPauseState(false);
|
||
if (!m_sendHistoryDialog->isTimingActive())
|
||
{
|
||
m_sendHistoryDialog->startTimingCount();
|
||
}
|
||
}
|
||
|
||
// 更新UI状态
|
||
ui->RegularlySentButton->setText("停止发送");
|
||
ui->NewRegularSentButton->setText("停止发送");
|
||
|
||
// 重新启动定时器
|
||
regularTimer->start();
|
||
|
||
qDebug() << QString("定时发送已恢复,当前累计时间:%1秒").arg(elapsedSeconds);
|
||
}
|
||
}
|
||
}
|
||
|
||
MainWindow::DeviceCommSettings MainWindow::parseCommSettingsString(const QString& commString)
|
||
{
|
||
// 默认通信设置
|
||
DeviceCommSettings settings;
|
||
settings.baudRate = 115200;
|
||
settings.dataBits = QSerialPort::Data8;
|
||
settings.parity = QSerialPort::NoParity;
|
||
settings.stopBits = QSerialPort::OneStop;
|
||
settings.portName = "";
|
||
|
||
// 解析格式示例: "115200 COM1" 或 "9600 COM3 8N1"
|
||
if (!commString.isEmpty())
|
||
{
|
||
QStringList parts = commString.split(" ", QString::SkipEmptyParts);
|
||
|
||
if (parts.size() >= 1)
|
||
{
|
||
// 尝试解析波特率
|
||
bool ok;
|
||
int baudRate = parts[0].toInt(&ok);
|
||
if (ok)
|
||
settings.baudRate = baudRate;
|
||
}
|
||
|
||
if (parts.size() >= 2)
|
||
{
|
||
// 解析端口名
|
||
if (parts[1].startsWith("COM", Qt::CaseInsensitive))
|
||
{
|
||
settings.portName = parts[1].trimmed();
|
||
}
|
||
}
|
||
|
||
if (parts.size() >= 3)
|
||
{
|
||
// 解析数据位、奇偶校验、停止位 (如 "8N1")
|
||
QString format = parts[2];
|
||
if (format.length() >= 3)
|
||
{
|
||
// 数据位
|
||
if (format[0] == '5')
|
||
settings.dataBits = QSerialPort::Data5;
|
||
else if (format[0] == '6')
|
||
settings.dataBits = QSerialPort::Data6;
|
||
else if (format[0] == '7')
|
||
settings.dataBits = QSerialPort::Data7;
|
||
else
|
||
settings.dataBits = QSerialPort::Data8;
|
||
|
||
// 校验位
|
||
if (format[1] == 'N' || format[1] == 'n')
|
||
settings.parity = QSerialPort::NoParity;
|
||
else if (format[1] == 'E' || format[1] == 'e')
|
||
settings.parity = QSerialPort::EvenParity;
|
||
else if (format[1] == 'O' || format[1] == 'o')
|
||
settings.parity = QSerialPort::OddParity;
|
||
|
||
// 停止位
|
||
if (format[2] == '2')
|
||
settings.stopBits = QSerialPort::TwoStop;
|
||
else
|
||
settings.stopBits = QSerialPort::OneStop;
|
||
}
|
||
}
|
||
}
|
||
|
||
return settings;
|
||
}
|
||
|
||
bool MainWindow::sendDataToDevice(const QString& portName, const QString& data)
|
||
{
|
||
// 如果是主串口,直接使用writeData方法
|
||
if (portName == m_serialPort->portName())
|
||
{
|
||
writeData(data);
|
||
return true;
|
||
}
|
||
|
||
// 检查是否有该串口的实例
|
||
if (!m_serialPorts.contains(portName))
|
||
{
|
||
return false;
|
||
}
|
||
|
||
// 获取串口实例
|
||
QSerialPort* port = m_serialPorts[portName];
|
||
if (!port->isOpen())
|
||
{
|
||
return false;
|
||
}
|
||
|
||
// 发送数据
|
||
QByteArray arr;
|
||
if (ui->isHexCheckBox->isChecked())
|
||
{
|
||
arr = QString2Hex(data);
|
||
}
|
||
else
|
||
{
|
||
arr = data.toLatin1();
|
||
}
|
||
|
||
qint64 bytesWritten = port->write(arr);
|
||
return (bytesWritten == arr.size());
|
||
}
|
||
|
||
// void MainWindow::updateSendHistory(const QString &command, const QString &portName,
|
||
// int baudRate, const QString &cmdName)
|
||
// {
|
||
// // 显示发送历史对话框
|
||
// showSendHistoryDialog();
|
||
|
||
// if (m_sendHistoryDialog) {
|
||
// // 添加记录到历史对话框
|
||
// QString displayCommand;
|
||
|
||
// // 如果有指令名称且不为空,加上指令名称前缀
|
||
// if (!cmdName.isEmpty()) {
|
||
// if (portName != m_serialPort->portName()) {
|
||
// // 如果不是主串口,加上端口标识
|
||
// displayCommand = QString("[%1] %2 -> %3").arg(cmdName).arg(command).arg(portName);
|
||
// } else {
|
||
// displayCommand = QString("[%1] %2").arg(cmdName).arg(command);
|
||
// }
|
||
// } else {
|
||
// // 没有指令名称,只显示通讯协议
|
||
// if (portName != m_serialPort->portName()) {
|
||
// // 如果不是主串口,加上端口标识
|
||
// displayCommand = command + " -> " + portName;
|
||
// } else {
|
||
// displayCommand = command;
|
||
// }
|
||
// }
|
||
|
||
// bool isHex = ui->isHexCheckBox->isChecked();
|
||
// m_sendHistoryDialog->addSendRecord(displayCommand, isHex);
|
||
// }
|
||
// }
|
||
|
||
// 修改 updateSendHistory 方法,添加 isHex 参数并使用它
|
||
void MainWindow::updateSendHistory(const QString& command, const QString& portName,
|
||
int baudRate, const QString& cmdName, bool isHex)
|
||
{
|
||
// 显示发送历史对话框
|
||
showSendHistoryDialog();
|
||
|
||
if (m_sendHistoryDialog)
|
||
{
|
||
// 添加记录到历史对话框
|
||
QString displayCommand;
|
||
|
||
// 如果有指令名称且不为空,加上指令名称前缀
|
||
if (!cmdName.isEmpty())
|
||
{
|
||
displayCommand = QString("[%1] %2 -> %3").arg(cmdName).arg(command).arg(portName);
|
||
}
|
||
else
|
||
{
|
||
displayCommand = QString("%1 -> %2").arg(command).arg(portName);
|
||
}
|
||
|
||
// 使用传入的实际格式标志,而不是全局设置
|
||
m_sendHistoryDialog->addSendRecord(displayCommand, isHex);
|
||
}
|
||
}
|
||
|
||
void MainWindow::on_startLogButton_clicked()
|
||
{
|
||
QString logFilePath = QFileDialog::getSaveFileName(
|
||
this,
|
||
tr("保存日志文件"),
|
||
QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") + ".log",
|
||
tr("日志文件 (*.log);;文本文件 (*.txt);;所有文件 (*.*)"));
|
||
|
||
if (logFilePath.isEmpty())
|
||
{
|
||
return; // 用户取消选择
|
||
}
|
||
|
||
if (m_logRecord->startLog(logFilePath))
|
||
{
|
||
CommonHelper::ShowMessageBoxInfo(tr("日志记录已开始"));
|
||
ui->startLogButton->setEnabled(false);
|
||
ui->stopLogButton->setEnabled(true);
|
||
}
|
||
else
|
||
{
|
||
CommonHelper::ShowMessageBoxError(tr("无法开始日志记录,请检查文件路径是否有效"));
|
||
}
|
||
}
|
||
|
||
void MainWindow::on_stopLogButton_clicked()
|
||
{
|
||
if (m_logRecord->isLogging())
|
||
{
|
||
m_logRecord->stopLog();
|
||
CommonHelper::ShowMessageBoxInfo(tr("日志记录已停止"));
|
||
ui->startLogButton->setEnabled(true);
|
||
ui->stopLogButton->setEnabled(false);
|
||
}
|
||
}
|
||
|
||
void MainWindow::on_refreshPortsButton_clicked()
|
||
{
|
||
updatePortsInComboBoxes();
|
||
CommonHelper::ShowMessageBoxInfo(tr("串口列表已更新"));
|
||
}
|
||
|
||
// void MainWindow::on_RegularlySentButton_clicked()
|
||
// {
|
||
// // 如果当前是暂停状态,重新启动定时发送
|
||
// if (isRegularSending && isPausedSending) {
|
||
// handlePauseRegularSending(false); // 恢复发送
|
||
// return;
|
||
// }
|
||
|
||
// if (!isRegularSending) {
|
||
// // 准备命令列表
|
||
// commandsWithComm.clear();
|
||
// currentCommandIndex = 0;
|
||
// elapsedSeconds = 0; // 重置累计秒数
|
||
|
||
// // 从表格中读取所有有效的命令及其时间点
|
||
// for (int i = 0; i < ui->tableWidget->rowCount(); i++) {
|
||
// if (ui->tableWidget->item(i, 17) && ui->tableWidget->item(i, 1) &&
|
||
// ui->tableWidget->item(i, 17)->checkState() == Qt::Checked) {
|
||
|
||
// int timePoint = ui->tableWidget->item(i, 1)->text().toInt();
|
||
// if (timePoint < 0) timePoint = 0; // 确保时间点不为负数
|
||
|
||
// checkAndAddDeviceCommand(i, 2, 3, 4, timePoint); // 设备1
|
||
// checkAndAddDeviceCommand(i, 5, 6, 7, timePoint); // 设备2
|
||
// checkAndAddDeviceCommand(i, 8, 9, 10, timePoint); // 设备3
|
||
// checkAndAddDeviceCommand(i, 11, 12, 13, timePoint); // 设备4
|
||
// checkAndAddDeviceCommand(i, 14, 15, 16, timePoint); // 设备5
|
||
// }
|
||
// }
|
||
|
||
// if (commandsWithComm.isEmpty()) {
|
||
// CommonHelper::ShowMessageBoxError(tr("没有找到有效的设备协议配置!"));
|
||
// return;
|
||
// }
|
||
|
||
// // 按时间点排序命令列表
|
||
// std::sort(commandsWithComm.begin(), commandsWithComm.end(),
|
||
// [](const DeviceCommand &a, const DeviceCommand &b) {
|
||
// return a.interval < b.interval; // interval现在表示时间点
|
||
// });
|
||
|
||
// if (!m_serialPort->isOpen()) {
|
||
// // if (ui->NewComcomboBox->currentText().isEmpty() && ui->comComboBox->currentText().isEmpty()) {
|
||
// // CommonHelper::ShowMessageBoxError(tr("请先选择串口!"));
|
||
// // return;
|
||
// // }
|
||
// // 如果串口未打开,尝试自动打开串口
|
||
// if (ui->NewComcomboBox->currentText().isEmpty() && ui->comComboBox->currentText().isEmpty()) {
|
||
// CommonHelper::ShowMessageBoxError(tr("请先选择串口!"));
|
||
// updatePortsInComboBoxes(); // 自动刷新串口列表
|
||
// return;
|
||
// }
|
||
|
||
// updateComSettings();
|
||
// m_serialPort->setPortName(currentSettings.name);
|
||
// m_serialPort->setBaudRate(currentSettings.baudRate);
|
||
// m_serialPort->setDataBits(currentSettings.dataBits);
|
||
// m_serialPort->setParity(currentSettings.parity);
|
||
// m_serialPort->setStopBits(currentSettings.stopBits);
|
||
|
||
// if (!m_serialPort->open(QIODevice::ReadWrite)) {
|
||
// CommonHelper::ShowMessageBoxError(tr("无法自动打开串口:%1").arg(m_serialPort->errorString()));
|
||
// return;
|
||
// }
|
||
|
||
// ui->connectInfo->setPixmap(QPixmap(":/skin/image/info.png"));
|
||
// ui->connectInfo->setScaledContents(true);
|
||
// ui->connectBtn->setText("关闭串口");
|
||
// ui->NewOpenComButton->setText("关闭串口");
|
||
// ui->NewRegularSentButton->setEnabled(true);
|
||
|
||
// CommonHelper::ShowMessageBoxInfo(tr("串口已自动打开,开始定时发送"));
|
||
// }
|
||
|
||
// regularTimer->start(); // 每秒检查一次
|
||
// isRegularSending = true;
|
||
// isPausedSending = false; // 确保重置暂停状态
|
||
// ui->RegularlySentButton->setText("停止发送");
|
||
// ui->NewRegularSentButton->setText("停止发送");
|
||
|
||
// showSendHistoryDialog();
|
||
// if (m_sendHistoryDialog) {
|
||
// m_sendHistoryDialog->setPauseState(false); // 确保重置历史对话框的暂停状态
|
||
// }
|
||
|
||
// // 启动累计时间计时器
|
||
// if (m_sendHistoryDialog && !m_sendHistoryDialog->isTimingActive()) {
|
||
// m_sendHistoryDialog->startTimingCount();
|
||
// }
|
||
// } else {
|
||
// // 无论是正在发送还是暂停状态,都停止定时发送
|
||
// regularTimer->stop();
|
||
// isRegularSending = false;
|
||
// isPausedSending = false; // 确保重置暂停状态
|
||
// elapsedSeconds = 0; // 重置累计秒数
|
||
// ui->RegularlySentButton->setText("定时发送");
|
||
// ui->NewRegularSentButton->setText("定时发送");
|
||
|
||
// if (m_sendHistoryDialog) {
|
||
// m_sendHistoryDialog->setPauseState(false); // 确保重置历史对话框的暂停状态
|
||
// }
|
||
|
||
// // 停止累计时间计时器
|
||
// if (m_sendHistoryDialog && m_sendHistoryDialog->isTimingActive()) {
|
||
// m_sendHistoryDialog->stopTimingCount();
|
||
// }
|
||
|
||
// CommonHelper::ShowMessageBoxInfo(tr("定时发送已停止"));
|
||
// }
|
||
// }
|
||
|
||
void MainWindow::on_RegularlySentButton_clicked()
|
||
{
|
||
// 如果当前是暂停状态,重新启动定时发送
|
||
if (isRegularSending && isPausedSending)
|
||
{
|
||
handlePauseRegularSending(false); // 恢复发送
|
||
return;
|
||
}
|
||
|
||
if (!isRegularSending)
|
||
{
|
||
// 准备命令列表
|
||
commandsWithComm.clear();
|
||
currentCommandIndex = 0;
|
||
elapsedSeconds = 0; // 重置累计秒数
|
||
|
||
// 从表格中读取所有有效的命令及其时间点
|
||
for (int i = 0; i < ui->tableWidget->rowCount(); i++)
|
||
{
|
||
if (ui->tableWidget->item(i, COLUMN_VALID) && ui->tableWidget->item(i, 1) &&
|
||
ui->tableWidget->item(i, COLUMN_VALID)->checkState() == Qt::Checked)
|
||
{
|
||
|
||
int timePoint = ui->tableWidget->item(i, 1)->text().toInt();
|
||
if (timePoint < 0)
|
||
timePoint = 0; // 确保时间点不为负数
|
||
|
||
checkAndAddDeviceCommand(i, 2, 3, 4, timePoint); // 设备1
|
||
checkAndAddDeviceCommand(i, 5, 6, 7, timePoint); // 设备2
|
||
checkAndAddDeviceCommand(i, 8, 9, 10, timePoint); // 设备3
|
||
checkAndAddDeviceCommand(i, 11, 12, 13, timePoint); // 设备4
|
||
checkAndAddDeviceCommand(i, 14, 15, 16, timePoint); // 设备5
|
||
}
|
||
}
|
||
|
||
if (commandsWithComm.isEmpty())
|
||
{
|
||
CommonHelper::ShowMessageBoxError(tr("没有找到有效的设备协议配置!"));
|
||
return;
|
||
}
|
||
|
||
// 按时间点排序命令列表
|
||
std::sort(commandsWithComm.begin(), commandsWithComm.end(),
|
||
[](const DeviceCommand & a, const DeviceCommand & b)
|
||
{
|
||
return a.interval < b.interval; // interval现在表示时间点
|
||
});
|
||
|
||
// 直接开始定时发送,不检查串口状态
|
||
regularTimer->start(); // 每秒检查一次
|
||
isRegularSending = true;
|
||
isPausedSending = false; // 确保重置暂停状态
|
||
ui->RegularlySentButton->setText("停止发送");
|
||
ui->NewRegularSentButton->setText("停止发送");
|
||
|
||
showSendHistoryDialog();
|
||
if (m_sendHistoryDialog)
|
||
{
|
||
m_sendHistoryDialog->setPauseState(false); // 确保重置历史对话框的暂停状态
|
||
}
|
||
|
||
// 启动累计时间计时器
|
||
if (m_sendHistoryDialog && !m_sendHistoryDialog->isTimingActive())
|
||
{
|
||
m_sendHistoryDialog->startTimingCount();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 无论是正在发送还是暂停状态,都停止定时发送
|
||
regularTimer->stop();
|
||
isRegularSending = false;
|
||
isPausedSending = false; // 确保重置暂停状态
|
||
elapsedSeconds = 0; // 重置累计秒数
|
||
ui->RegularlySentButton->setText("定时发送");
|
||
ui->NewRegularSentButton->setText("定时发送");
|
||
|
||
if (m_sendHistoryDialog)
|
||
{
|
||
m_sendHistoryDialog->setPauseState(false); // 确保重置历史对话框的暂停状态
|
||
}
|
||
|
||
// 停止累计时间计时器
|
||
if (m_sendHistoryDialog && m_sendHistoryDialog->isTimingActive())
|
||
{
|
||
m_sendHistoryDialog->stopTimingCount();
|
||
}
|
||
|
||
CommonHelper::ShowMessageBoxInfo(tr("定时发送已停止"));
|
||
}
|
||
}
|
||
|
||
void MainWindow::on_NewRegularSentButton_clicked()
|
||
{
|
||
// 如果当前是暂停状态,重新启动定时发送
|
||
if (isRegularSending && isPausedSending)
|
||
{
|
||
handlePauseRegularSending(false); // 恢复发送
|
||
return;
|
||
}
|
||
|
||
// 调用主定时发送按钮的功能
|
||
on_RegularlySentButton_clicked();
|
||
}
|
||
|
||
void MainWindow::synchronizeComboBoxes()
|
||
{
|
||
QComboBox* senderBox = qobject_cast<QComboBox*>(QObject::sender());
|
||
|
||
if (senderBox == ui->comComboBox)
|
||
{
|
||
ui->NewComcomboBox->blockSignals(true);
|
||
ui->NewComcomboBox->setCurrentIndex(ui->comComboBox->currentIndex());
|
||
ui->NewComcomboBox->blockSignals(false);
|
||
}
|
||
else if (senderBox == ui->NewComcomboBox)
|
||
{
|
||
ui->comComboBox->blockSignals(true);
|
||
ui->comComboBox->setCurrentIndex(ui->NewComcomboBox->currentIndex());
|
||
ui->comComboBox->blockSignals(false);
|
||
}
|
||
}
|
||
|
||
void MainWindow::onSendButtonClicked()
|
||
{
|
||
QPushButton* button = qobject_cast<QPushButton*>(sender());
|
||
if (!button)
|
||
return;
|
||
|
||
int row = button->property("row").toInt();
|
||
|
||
if (row >= 0 && row < ui->tableWidget->rowCount() && m_serialPort->isOpen())
|
||
{
|
||
if (ui->tableWidget->item(row, 3) && !ui->tableWidget->item(row, 3)->text().isEmpty())
|
||
{
|
||
QString command = ui->tableWidget->item(row, 3)->text();
|
||
writeData(command);
|
||
}
|
||
else
|
||
{
|
||
CommonHelper::ShowMessageBoxError(tr("该行没有有效的发送命令!"));
|
||
}
|
||
}
|
||
else if (!m_serialPort->isOpen())
|
||
{
|
||
CommonHelper::ShowMessageBoxError(tr("请先打开串口!"));
|
||
}
|
||
}
|
||
|
||
void MainWindow::onMultiDeviceSendButtonClicked()
|
||
{
|
||
QPushButton* button = qobject_cast<QPushButton*>(sender());
|
||
if (!button)
|
||
return;
|
||
|
||
int row = button->property("row").toInt();
|
||
|
||
if (row >= 0 && row < ui->tableWidget->rowCount() /*&& m_serialPort->isOpen()*/)
|
||
{
|
||
bool anySent = false;
|
||
|
||
// if (trySendDeviceCommand(row, 2, 3, 4)) anySent = true;
|
||
// if (trySendDeviceCommand(row, 5, 6, 7)) anySent = true;
|
||
// if (trySendDeviceCommand(row, 8, 9, 10)) anySent = true;
|
||
// if (trySendDeviceCommand(row, 11, 12, 13)) anySent = true;
|
||
// if (trySendDeviceCommand(row, 14, 15, 16)) anySent = true;
|
||
if (trySendMQTTCommand(row, 17, 18, 19, 20))
|
||
anySent = true;
|
||
|
||
if (!anySent)
|
||
{
|
||
CommonHelper::ShowMessageBoxError(tr("该行没有配置任何设备命令!"));
|
||
}
|
||
}
|
||
else if (!m_serialPort->isOpen())
|
||
{
|
||
CommonHelper::ShowMessageBoxError(tr("请先打开串口!"));
|
||
}
|
||
}
|
||
|
||
// 修改 sendRegularCommandWithPort 方法中的数据发送部分
|
||
void MainWindow::sendRegularCommandWithPort()
|
||
{
|
||
if (commandsWithComm.isEmpty())
|
||
{
|
||
regularTimer->stop();
|
||
isRegularSending = false;
|
||
isPausedSending = false;
|
||
elapsedSeconds = 0;
|
||
ui->RegularlySentButton->setText("定时发送");
|
||
ui->NewRegularSentButton->setText("定时发送");
|
||
return;
|
||
}
|
||
|
||
// 增加累计秒数
|
||
elapsedSeconds++;
|
||
|
||
// 检查是否有需要在当前时间点发送的命令
|
||
for (int i = 0; i < commandsWithComm.size(); i++)
|
||
{
|
||
const DeviceCommand& cmd = commandsWithComm.at(i);
|
||
|
||
// 如果命令的时间点等于当前累计秒数,则发送
|
||
if (cmd.interval == elapsedSeconds)
|
||
{
|
||
// 解析通讯参数
|
||
DeviceCommSettings commSettings = parseCommSettingsString(cmd.commParam);
|
||
|
||
// 检查端口名是否有效
|
||
if (commSettings.portName.isEmpty())
|
||
{
|
||
qDebug() << "命令" << cmd.command << "的端口名称为空,跳过发送";
|
||
continue;
|
||
}
|
||
|
||
// 检查是否是主串口
|
||
bool isMainPort = false;
|
||
if (m_serialPort->isOpen() && m_serialPort->portName() == commSettings.portName)
|
||
{
|
||
isMainPort = true;
|
||
|
||
// 根据命令的格式发送数据,而不是根据全局设置
|
||
QByteArray arr;
|
||
if (cmd.isHex)
|
||
{
|
||
arr = QString2Hex(cmd.command);
|
||
m_serialPort->write(arr);
|
||
|
||
// 在发送编辑框中显示
|
||
ui->sendTextEdit->append(cmd.command.toUpper());
|
||
}
|
||
else
|
||
{
|
||
arr = cmd.command.toUtf8(); // 使用UTF-8编码ASCII文本
|
||
m_serialPort->write(arr);
|
||
|
||
// 在发送编辑框中显示
|
||
ui->sendTextEdit->append(cmd.command);
|
||
}
|
||
|
||
// 更新计数
|
||
sendCount += arr.size();
|
||
ui->sendCountLabel->setNum(sendCount);
|
||
|
||
// 记录日志
|
||
if (m_logRecord->isLogging())
|
||
{
|
||
if (cmd.isHex)
|
||
{
|
||
m_logRecord->logSend(cmd.command.toUpper());
|
||
}
|
||
else
|
||
{
|
||
m_logRecord->logSend(cmd.command);
|
||
}
|
||
}
|
||
|
||
// 添加到发送历史记录
|
||
updateSendHistory(cmd.command, commSettings.portName,
|
||
commSettings.baudRate, cmd.protocol, cmd.isHex);
|
||
|
||
qDebug() << "通过主串口" << commSettings.portName << "发送"
|
||
<< (cmd.isHex ? "HEX" : "ASCII") << "命令:" << cmd.command;
|
||
continue;
|
||
}
|
||
|
||
// 如果不是主串口,尝试找或创建特定串口
|
||
QSerialPort* targetPort = nullptr;
|
||
|
||
// 检查此端口是否已经创建和打开
|
||
if (m_serialPorts.contains(commSettings.portName))
|
||
{
|
||
targetPort = m_serialPorts[commSettings.portName];
|
||
|
||
// 如果端口已经打开但参数不同,需要重新配置
|
||
if (targetPort->isOpen() &&
|
||
(targetPort->baudRate() != commSettings.baudRate ||
|
||
targetPort->dataBits() != commSettings.dataBits ||
|
||
targetPort->parity() != commSettings.parity ||
|
||
targetPort->stopBits() != commSettings.stopBits))
|
||
{
|
||
|
||
targetPort->close();
|
||
}
|
||
}
|
||
|
||
// 如果串口不存在或已关闭,需要创建或打开
|
||
if (!targetPort || !targetPort->isOpen())
|
||
{
|
||
bool result = openSerialPortForDevice(
|
||
commSettings.portName,
|
||
commSettings.baudRate,
|
||
commSettings.dataBits,
|
||
commSettings.parity,
|
||
commSettings.stopBits
|
||
);
|
||
|
||
if (!result)
|
||
{
|
||
qDebug() << "无法打开串口" << commSettings.portName << ",跳过命令" << cmd.command;
|
||
continue;
|
||
}
|
||
|
||
targetPort = m_serialPorts[commSettings.portName];
|
||
}
|
||
|
||
// 根据命令的格式发送数据
|
||
QByteArray arr;
|
||
if (cmd.isHex)
|
||
{
|
||
arr = QString2Hex(cmd.command);
|
||
}
|
||
else
|
||
{
|
||
arr = cmd.command.toUtf8(); // 使用UTF-8编码ASCII文本
|
||
}
|
||
|
||
qint64 bytesWritten = targetPort->write(arr);
|
||
if (bytesWritten != arr.size())
|
||
{
|
||
qDebug() << "发送数据到串口" << commSettings.portName << "失败";
|
||
}
|
||
else
|
||
{
|
||
qDebug() << "成功发送" << (cmd.isHex ? "HEX" : "ASCII") << "命令到串口"
|
||
<< commSettings.portName << ":" << cmd.command;
|
||
|
||
// 在发送窗口添加发送记录
|
||
QString displayText;
|
||
if (!cmd.protocol.isEmpty())
|
||
{
|
||
displayText = QString("[%1] %2 -> %3").arg(cmd.protocol).arg(cmd.command).arg(commSettings.portName);
|
||
}
|
||
else
|
||
{
|
||
displayText = QString("%1 -> %2").arg(cmd.command).arg(commSettings.portName);
|
||
}
|
||
|
||
if (cmd.isHex)
|
||
{
|
||
ui->sendTextEdit->append(displayText.toUpper());
|
||
}
|
||
else
|
||
{
|
||
ui->sendTextEdit->append(displayText);
|
||
}
|
||
|
||
// 更新发送计数
|
||
sendCount += arr.size();
|
||
ui->sendCountLabel->setNum(sendCount);
|
||
|
||
// 添加到发送历史记录
|
||
updateSendHistory(cmd.command, commSettings.portName,
|
||
commSettings.baudRate, cmd.protocol, cmd.isHex);
|
||
|
||
// 记录发送的日志
|
||
if (m_logRecord->isLogging())
|
||
{
|
||
if (cmd.isHex)
|
||
{
|
||
m_logRecord->logSend(displayText.toUpper());
|
||
}
|
||
else
|
||
{
|
||
m_logRecord->logSend(displayText);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// void MainWindow::sendRegularCommandWithPort()
|
||
// {
|
||
// if (commandsWithComm.isEmpty()) {
|
||
// regularTimer->stop();
|
||
// isRegularSending = false;
|
||
// isPausedSending = false;
|
||
// elapsedSeconds = 0;
|
||
// ui->RegularlySentButton->setText("定时发送");
|
||
// ui->NewRegularSentButton->setText("定时发送");
|
||
// return;
|
||
// }
|
||
|
||
// // 增加累计秒数
|
||
// elapsedSeconds++;
|
||
|
||
// // 检查是否有需要在当前时间点发送的命令
|
||
// for (int i = 0; i < commandsWithComm.size(); i++) {
|
||
// const DeviceCommand &cmd = commandsWithComm.at(i);
|
||
|
||
// // 如果命令的时间点等于当前累计秒数,则发送
|
||
// if (cmd.interval == elapsedSeconds) {
|
||
// // 解析通讯参数
|
||
// DeviceCommSettings commSettings = parseCommSettingsString(cmd.commParam);
|
||
|
||
// // 检查端口名是否有效
|
||
// if (commSettings.portName.isEmpty()) {
|
||
// qDebug() << "命令" << cmd.command << "的端口名称为空,跳过发送";
|
||
// continue;
|
||
// }
|
||
|
||
// // 检查是否是主串口
|
||
// bool isMainPort = false;
|
||
// if (m_serialPort->isOpen() && m_serialPort->portName() == commSettings.portName) {
|
||
// isMainPort = true;
|
||
// writeData(cmd.command);
|
||
// qDebug() << "通过主串口" << commSettings.portName << "发送命令:" << cmd.command;
|
||
|
||
// // 添加到发送历史记录 - 包含指令名称
|
||
// updateSendHistory(cmd.command, commSettings.portName, commSettings.baudRate, cmd.protocol);
|
||
// continue;
|
||
// }
|
||
|
||
// // 如果不是主串口,尝试找或创建特定串口
|
||
// QSerialPort *targetPort = nullptr;
|
||
|
||
// // 检查此端口是否已经创建和打开
|
||
// if (m_serialPorts.contains(commSettings.portName)) {
|
||
// targetPort = m_serialPorts[commSettings.portName];
|
||
|
||
// // 如果端口已经打开但参数不同,需要重新配置
|
||
// if (targetPort->isOpen() &&
|
||
// (targetPort->baudRate() != commSettings.baudRate ||
|
||
// targetPort->dataBits() != commSettings.dataBits ||
|
||
// targetPort->parity() != commSettings.parity ||
|
||
// targetPort->stopBits() != commSettings.stopBits)) {
|
||
|
||
// targetPort->close();
|
||
// }
|
||
// }
|
||
|
||
// // 如果串口不存在或已关闭,需要创建或打开
|
||
// if (!targetPort || !targetPort->isOpen()) {
|
||
// bool result = openSerialPortForDevice(
|
||
// commSettings.portName,
|
||
// commSettings.baudRate,
|
||
// commSettings.dataBits,
|
||
// commSettings.parity,
|
||
// commSettings.stopBits
|
||
// );
|
||
|
||
// if (!result) {
|
||
// qDebug() << "无法打开串口" << commSettings.portName << ",跳过命令" << cmd.command;
|
||
// continue;
|
||
// }
|
||
|
||
// targetPort = m_serialPorts[commSettings.portName];
|
||
// }
|
||
|
||
// // 发送数据
|
||
// QByteArray arr;
|
||
// if (ui->isHexCheckBox->isChecked()) {
|
||
// arr = QString2Hex(cmd.command);
|
||
// } else {
|
||
// arr = cmd.command.toLatin1();
|
||
// }
|
||
|
||
// qint64 bytesWritten = targetPort->write(arr);
|
||
// if (bytesWritten != arr.size()) {
|
||
// qDebug() << "发送数据到串口" << commSettings.portName << "失败";
|
||
// } else {
|
||
// qDebug() << "成功发送到串口" << commSettings.portName << ":" << cmd.command;
|
||
|
||
// // 在发送窗口添加发送记录
|
||
// QString displayText;
|
||
// if (!cmd.protocol.isEmpty()) {
|
||
// displayText = QString("[%1] %2 -> %3").arg(cmd.protocol).arg(cmd.command).arg(commSettings.portName);
|
||
// } else {
|
||
// displayText = QString("%1 -> %2").arg(cmd.command).arg(commSettings.portName);
|
||
// }
|
||
|
||
// if (ui->isHexCheckBox->isChecked()) {
|
||
// ui->sendTextEdit->append(displayText.toUpper());
|
||
// } else {
|
||
// ui->sendTextEdit->append(displayText);
|
||
// }
|
||
|
||
// // 更新发送计数
|
||
// sendCount += arr.size();
|
||
// ui->sendCountLabel->setNum(sendCount);
|
||
|
||
// // 添加到发送历史记录 - 包含指令名称
|
||
// updateSendHistory(cmd.command, commSettings.portName, commSettings.baudRate, cmd.protocol);
|
||
|
||
// // 记录发送的日志 - 添加指令名称
|
||
// if (m_logRecord->isLogging()) {
|
||
// if (ui->isHexCheckBox->isChecked()) {
|
||
// m_logRecord->logSend(displayText.toUpper());
|
||
// } else {
|
||
// m_logRecord->logSend(displayText);
|
||
// }
|
||
// }
|
||
// }
|
||
// }
|
||
// }
|
||
// }
|
||
|
||
// void MainWindow::handleSerialPortError(QSerialPort::SerialPortError error)
|
||
// {
|
||
// QSerialPort *port = qobject_cast<QSerialPort*>(sender());
|
||
// if (!port) return;
|
||
|
||
// if (error != QSerialPort::NoError && error != QSerialPort::NotOpenError) {
|
||
// QString portName = port->portName();
|
||
// QString errorMsg = port->errorString();
|
||
|
||
// CommonHelper::ShowMessageBoxError(tr("串口 %1 发生错误: %2").arg(portName).arg(errorMsg));
|
||
|
||
// if (port == m_serialPort) {
|
||
// ui->connectInfo->setPixmap(QPixmap(":/skin/image/error.png"));
|
||
// ui->connectInfo->setScaledContents(true);
|
||
// ui->connectBtn->setText("打开串口");
|
||
// ui->NewOpenComButton->setText("打开串口");
|
||
|
||
// if (isRegularSending) {
|
||
// regularTimer->stop();
|
||
// isRegularSending = false;
|
||
// isPausedSending = false;
|
||
// ui->RegularlySentButton->setText("定时发送");
|
||
// ui->NewRegularSentButton->setText("定时发送");
|
||
// }
|
||
|
||
// ui->NewRegularSentButton->setEnabled(false);
|
||
// }
|
||
// }
|
||
// }
|
||
|
||
void MainWindow::handleSerialPortError(QSerialPort::SerialPortError error)
|
||
{
|
||
QSerialPort* port = qobject_cast<QSerialPort*>(sender());
|
||
if (!port)
|
||
return;
|
||
|
||
if (error != QSerialPort::NoError && error != QSerialPort::NotOpenError)
|
||
{
|
||
QString portName = port->portName();
|
||
QString errorMsg = port->errorString();
|
||
|
||
CommonHelper::ShowMessageBoxError(tr("串口 %1 发生错误: %2").arg(portName).arg(errorMsg));
|
||
|
||
if (port == m_serialPort)
|
||
{
|
||
ui->connectInfo->setPixmap(QPixmap(":/skin/image/error.png"));
|
||
ui->connectInfo->setScaledContents(true);
|
||
ui->connectBtn->setText("打开串口");
|
||
ui->NewOpenComButton->setText("打开串口");
|
||
|
||
if (isRegularSending)
|
||
{
|
||
regularTimer->stop();
|
||
isRegularSending = false;
|
||
isPausedSending = false;
|
||
ui->RegularlySentButton->setText("定时发送");
|
||
ui->NewRegularSentButton->setText("定时发送");
|
||
}
|
||
|
||
// 删除这行,避免禁用定时发送按钮
|
||
// ui->NewRegularSentButton->setEnabled(false);
|
||
}
|
||
}
|
||
}
|
||
|
||
void MainWindow::checkAndAddDeviceCommand(int row, int cmdCol, int protocolCol, int commCol, int timePoint)
|
||
{
|
||
|
||
// 确保列索引在有效范围内
|
||
if (row < 0 || row >= ui->tableWidget->rowCount() ||
|
||
protocolCol >= ui->tableWidget->columnCount() ||
|
||
cmdCol >= ui->tableWidget->columnCount() ||
|
||
commCol >= ui->tableWidget->columnCount())
|
||
{
|
||
return;
|
||
}
|
||
|
||
// 检查协议列是否有效且不为空 - 修改为发送协议而非命令
|
||
if (ui->tableWidget->item(row, protocolCol) && !ui->tableWidget->item(row, protocolCol)->text().isEmpty())
|
||
{
|
||
DeviceCommand cmd;
|
||
// 将要发送的内容设为协议字段而非指令名称
|
||
cmd.command = ui->tableWidget->item(row, protocolCol)->text();
|
||
cmd.row = row;
|
||
cmd.deviceCol = cmdCol; // 保留设备列位置以便可能的引用
|
||
cmd.interval = timePoint; // 使用传入的时间点
|
||
|
||
// 检测这是否是Hex格式数据 - 通常Hex格式数据只包含0-9和A-F字符以及空格
|
||
QString cmdText = cmd.command;
|
||
QRegularExpression hexRegex("^[A-Fa-f0-9\\s]+$");
|
||
cmd.isHex = hexRegex.match(cmdText).hasMatch();
|
||
|
||
|
||
// 获取指令名称(作为备注或记录,但不发送)
|
||
if (ui->tableWidget->item(row, cmdCol))
|
||
{
|
||
cmd.protocol = ui->tableWidget->item(row, cmdCol)->text();
|
||
}
|
||
else
|
||
{
|
||
cmd.protocol = ""; // 如果指令名称为空,则使用空字符串
|
||
}
|
||
|
||
// 获取通信参数
|
||
if (ui->tableWidget->item(row, commCol))
|
||
{
|
||
cmd.commParam = ui->tableWidget->item(row, commCol)->text();
|
||
|
||
// 确保通信参数有效
|
||
if (cmd.commParam.isEmpty())
|
||
{
|
||
// 尝试使用当前选中的串口
|
||
if (!ui->NewComcomboBox->currentText().isEmpty())
|
||
{
|
||
QString portName = ui->NewComcomboBox->currentData().toString();
|
||
cmd.commParam = QString("%1 %2").arg(currentSettings.baudRate).arg(portName);
|
||
}
|
||
else if (!ui->comComboBox->currentText().isEmpty())
|
||
{
|
||
QString portName = ui->comComboBox->currentData().toString();
|
||
cmd.commParam = QString("%1 %2").arg(currentSettings.baudRate).arg(portName);
|
||
}
|
||
else
|
||
{
|
||
// 默认使用 COM1
|
||
cmd.commParam = "115200 COM1";
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 使用默认通信参数
|
||
cmd.commParam = "115200 COM1";
|
||
}
|
||
|
||
// 添加到命令列表
|
||
commandsWithComm.append(cmd);
|
||
qDebug() << "添加命令:" << cmd.protocol << "协议:" << cmd.command
|
||
<< "通信:" << cmd.commParam << "时间点:" << cmd.interval
|
||
<< "格式:" << (cmd.isHex ? "HEX" : "ASCII");
|
||
}
|
||
}
|
||
|
||
// 修改 trySendDeviceCommand 方法,兼容ASCII和HEX格式
|
||
bool MainWindow::trySendMQTTCommand(int row, int cmdCol, int protocolCol, int commCol, int topicCol)
|
||
{
|
||
// 检查协议列是否有效且不为空
|
||
if (ui->tableWidget->item(row, protocolCol) && !ui->tableWidget->item(row, protocolCol)->text().isEmpty())
|
||
{
|
||
// 获取要发送的协议
|
||
QString cmdName = ui->tableWidget->item(row, cmdCol)->text();
|
||
|
||
QString protocol = ui->tableWidget->item(row, protocolCol)->text();
|
||
|
||
// // 检测协议是否为HEX格式
|
||
// QRegularExpression hexRegex("^[A-Fa-f0-9\\s]+$");
|
||
// bool isHex = hexRegex.match(protocol).hasMatch();
|
||
|
||
// 获取指令名称(如果有)
|
||
QString topic;
|
||
if (ui->tableWidget->item(row, topicCol))
|
||
{
|
||
topic = ui->tableWidget->item(row, topicCol)->text();
|
||
}
|
||
|
||
// 获取通信参数(如果有)
|
||
QString commParam;
|
||
if (ui->tableWidget->item(row, commCol))
|
||
{
|
||
commParam = ui->tableWidget->item(row, commCol)->text();
|
||
}
|
||
|
||
// 如果有通信参数
|
||
MqttDealer* mqtt_s;
|
||
if (!commParam.isEmpty() && commParam.split(":").size() > 0)
|
||
{
|
||
// 检查此设备是否已经创建和打开
|
||
|
||
if (ConnectMQTTServer(commParam, mqtt_s))
|
||
{
|
||
// toDo 发送数据
|
||
m_mqttServers[commParam]->PublishDataByMQTT(ui->lineEdit_topic->text() + topic, protocol);
|
||
}
|
||
}
|
||
|
||
// 添加到发送历史记录
|
||
updateSendHistory(protocol, commParam, 0, cmdName, false);
|
||
|
||
QString displayCommand;
|
||
if (!cmdName.isEmpty())
|
||
{
|
||
displayCommand = QString("[%1] %2 -> %3").arg(cmdName).arg(protocol).arg(commParam);
|
||
}
|
||
else
|
||
{
|
||
displayCommand = QString("%1 -> %2").arg(protocol).arg(commParam);
|
||
}
|
||
|
||
// 记录发送的日志
|
||
if (m_logRecord->isLogging())
|
||
{
|
||
m_logRecord->logSend(displayCommand);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
// 修改 trySendDeviceCommand 方法,兼容ASCII和HEX格式
|
||
bool MainWindow::trySendDeviceCommand(int row, int cmdCol, int protocolCol, int commCol)
|
||
{
|
||
// 检查协议列是否有效且不为空
|
||
if (ui->tableWidget->item(row, protocolCol) && !ui->tableWidget->item(row, protocolCol)->text().isEmpty())
|
||
{
|
||
// 获取要发送的协议
|
||
QString protocol = ui->tableWidget->item(row, protocolCol)->text();
|
||
|
||
// 检测协议是否为HEX格式
|
||
QRegularExpression hexRegex("^[A-Fa-f0-9\\s]+$");
|
||
bool isHex = hexRegex.match(protocol).hasMatch();
|
||
|
||
// 获取指令名称(如果有)
|
||
QString cmdName;
|
||
if (ui->tableWidget->item(row, cmdCol))
|
||
{
|
||
cmdName = ui->tableWidget->item(row, cmdCol)->text();
|
||
}
|
||
|
||
// 获取通信参数(如果有)
|
||
QString commParam;
|
||
if (ui->tableWidget->item(row, commCol))
|
||
{
|
||
commParam = ui->tableWidget->item(row, commCol)->text();
|
||
}
|
||
|
||
// 如果有通信参数,尝试使用特定串口发送
|
||
if (!commParam.isEmpty())
|
||
{
|
||
// 解析通信参数
|
||
DeviceCommSettings commSettings = parseCommSettingsString(commParam);
|
||
|
||
// 如果指定了有效的串口名,且不是主串口,尝试使用特定串口发送
|
||
if (!commSettings.portName.isEmpty() &&
|
||
commSettings.portName != m_serialPort->portName())
|
||
{
|
||
|
||
QSerialPort* targetPort = nullptr;
|
||
|
||
// 检查此端口是否已经创建和打开
|
||
if (m_serialPorts.contains(commSettings.portName))
|
||
{
|
||
targetPort = m_serialPorts[commSettings.portName];
|
||
|
||
// 如果端口已经打开但参数不同,需要重新配置
|
||
if (targetPort->isOpen() &&
|
||
(targetPort->baudRate() != commSettings.baudRate ||
|
||
targetPort->dataBits() != commSettings.dataBits ||
|
||
targetPort->parity() != commSettings.parity ||
|
||
targetPort->stopBits() != commSettings.stopBits))
|
||
{
|
||
|
||
targetPort->close();
|
||
}
|
||
}
|
||
|
||
// 如果串口不存在或已关闭,需要创建或打开
|
||
if (!targetPort || !targetPort->isOpen())
|
||
{
|
||
bool result = openSerialPortForDevice(
|
||
commSettings.portName,
|
||
commSettings.baudRate,
|
||
commSettings.dataBits,
|
||
commSettings.parity,
|
||
commSettings.stopBits
|
||
);
|
||
|
||
if (!result)
|
||
{
|
||
qDebug() << "无法打开串口" << commSettings.portName << ",回退到主串口";
|
||
}
|
||
else
|
||
{
|
||
targetPort = m_serialPorts[commSettings.portName];
|
||
}
|
||
}
|
||
|
||
// 如果有可用的目标串口,发送数据
|
||
if (targetPort && targetPort->isOpen())
|
||
{
|
||
// 根据协议格式发送数据
|
||
QByteArray arr;
|
||
if (isHex)
|
||
{
|
||
arr = QString2Hex(protocol);
|
||
}
|
||
else
|
||
{
|
||
arr = protocol.toUtf8(); // 使用UTF-8编码ASCII文本
|
||
}
|
||
|
||
qint64 bytesWritten = targetPort->write(arr);
|
||
if (bytesWritten != arr.size())
|
||
{
|
||
qDebug() << "发送数据到串口" << commSettings.portName << "失败";
|
||
}
|
||
else
|
||
{
|
||
qDebug() << "成功发送" << (isHex ? "HEX" : "ASCII") << "命令到串口"
|
||
<< commSettings.portName << ":" << protocol;
|
||
|
||
// 在发送窗口添加发送记录
|
||
QString displayText;
|
||
if (!cmdName.isEmpty())
|
||
{
|
||
displayText = QString("[%1] %2 -> %3").arg(cmdName).arg(protocol).arg(commSettings.portName);
|
||
}
|
||
else
|
||
{
|
||
displayText = QString("%1 -> %2").arg(protocol).arg(m_serialPort->portName()); //arg(commSettings.portName);
|
||
}
|
||
|
||
if (isHex)
|
||
{
|
||
ui->sendTextEdit->append(displayText.toUpper());
|
||
}
|
||
else
|
||
{
|
||
ui->sendTextEdit->append(displayText);
|
||
}
|
||
|
||
// 更新发送计数
|
||
sendCount += arr.size();
|
||
ui->sendCountLabel->setNum(sendCount);
|
||
|
||
// 添加到发送历史记录
|
||
updateSendHistory(protocol, commSettings.portName, commSettings.baudRate, cmdName, isHex);
|
||
|
||
// 记录发送的日志
|
||
if (m_logRecord->isLogging())
|
||
{
|
||
if (isHex)
|
||
{
|
||
m_logRecord->logSend(displayText.toUpper());
|
||
}
|
||
else
|
||
{
|
||
m_logRecord->logSend(displayText);
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 回退到使用主串口发送
|
||
// 不再使用全局 isHexCheckBox,而是根据协议自身判断
|
||
QByteArray arr;
|
||
if (isHex)
|
||
{
|
||
arr = QString2Hex(protocol);
|
||
m_serialPort->write(arr);
|
||
|
||
// 在发送编辑框中显示
|
||
QString displayText = protocol;
|
||
if (!cmdName.isEmpty())
|
||
{
|
||
displayText = QString("[%1] %2").arg(cmdName).arg(protocol);
|
||
}
|
||
ui->sendTextEdit->append(displayText.toUpper());
|
||
}
|
||
else
|
||
{
|
||
arr = protocol.toUtf8();
|
||
m_serialPort->write(arr);
|
||
|
||
// 在发送编辑框中显示
|
||
QString displayText = protocol;
|
||
if (!cmdName.isEmpty())
|
||
{
|
||
displayText = QString("[%1] %2").arg(cmdName).arg(protocol);
|
||
}
|
||
ui->sendTextEdit->append(displayText);
|
||
}
|
||
|
||
// 更新计数
|
||
sendCount += arr.size();
|
||
ui->sendCountLabel->setNum(sendCount);
|
||
|
||
// 记录日志
|
||
if (m_logRecord->isLogging())
|
||
{
|
||
QString displayText = protocol;
|
||
if (!cmdName.isEmpty())
|
||
{
|
||
displayText = QString("[%1] %2").arg(cmdName).arg(protocol);
|
||
}
|
||
|
||
if (isHex)
|
||
{
|
||
m_logRecord->logSend(displayText.toUpper());
|
||
}
|
||
else
|
||
{
|
||
m_logRecord->logSend(displayText);
|
||
}
|
||
}
|
||
|
||
// 添加到发送历史记录
|
||
updateSendHistory(protocol, m_serialPort->portName(), currentSettings.baudRate, cmdName, isHex);
|
||
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
bool MainWindow::ConnectMQTTServer(const QString& ipport, MqttDealer* mqtt_s)
|
||
{
|
||
if (ipport.isEmpty())
|
||
{
|
||
qDebug() << "服务器ip为空,无法连接";
|
||
return false;
|
||
}
|
||
|
||
// 检查是否已有此端口实例
|
||
if (m_mqttServers.contains(ipport))
|
||
{
|
||
mqtt_s = m_mqttServers[ipport];
|
||
if (mqtt_s->IsOpen())
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 创建新服务器实例
|
||
mqtt_s = new MqttDealer();
|
||
}
|
||
|
||
// 设置参数
|
||
QStringList list = ipport.split(":");
|
||
if (list.size() <= 0)
|
||
{
|
||
return false;
|
||
}
|
||
if (!mqtt_s->Open(list.at(0).toStdString().c_str(), list[1].toInt()))
|
||
{
|
||
CommonHelper::ShowMessageBoxError(tr("当前MQTT通道%1连接失败!\n请选择其他通道," \
|
||
"或者检查MQTT设置是否正确。").arg(list.at(0) + ":" + list.at(1)));
|
||
return false;
|
||
}
|
||
|
||
m_mqttServers[ipport] = mqtt_s;
|
||
return true;
|
||
}
|
||
|
||
void MainWindow::DisconnectMQTTServer(const QString& ipport)
|
||
{
|
||
if (m_mqttServers.contains(ipport))
|
||
{
|
||
MqttDealer* mqtt_server = m_mqttServers[ipport];
|
||
if (mqtt_server->IsOpen())
|
||
{
|
||
mqtt_server->Close();
|
||
}
|
||
}
|
||
}
|
||
|
||
bool MainWindow::openSerialPortForDevice(const QString& portName, int baudRate, QSerialPort::DataBits dataBits,
|
||
QSerialPort::Parity parity, QSerialPort::StopBits stopBits)
|
||
{
|
||
if (portName.isEmpty())
|
||
{
|
||
qDebug() << "串口名称为空,无法打开串口";
|
||
return false;
|
||
}
|
||
|
||
// 如果是主串口且已打开,直接返回成功
|
||
if (m_serialPort->isOpen() && m_serialPort->portName() == portName)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
// 检查是否已有此端口实例
|
||
if (m_serialPorts.contains(portName))
|
||
{
|
||
QSerialPort* port = m_serialPorts[portName];
|
||
if (port->isOpen())
|
||
{
|
||
// 如果参数相同,不需要重新打开
|
||
if (port->baudRate() == baudRate &&
|
||
port->dataBits() == dataBits &&
|
||
port->parity() == parity &&
|
||
port->stopBits() == stopBits)
|
||
{
|
||
return true;
|
||
}
|
||
port->close(); // 关闭后重新设置参数
|
||
QThread::msleep(100); // 等待完全关闭
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 创建新串口实例
|
||
QSerialPort* port = new QSerialPort(this);
|
||
m_serialPorts[portName] = port;
|
||
|
||
// 连接错误信号
|
||
connect(port, SIGNAL(error(QSerialPort::SerialPortError)),
|
||
this, SLOT(handleSerialPortError(QSerialPort::SerialPortError)));
|
||
|
||
// 连接数据接收信号
|
||
connect(port, &QSerialPort::readyRead, [this, portName]()
|
||
{
|
||
if (m_serialPorts.contains(portName))
|
||
{
|
||
QSerialPort* port = m_serialPorts[portName];
|
||
QByteArray data = port->readAll();
|
||
if (!data.isEmpty())
|
||
{
|
||
QString str = ShowHex(data);
|
||
ui->receiveTextEdit->append("[" + portName + "] " + str.toUpper());
|
||
|
||
// 更新接收计数
|
||
receiveCount += data.count();
|
||
ui->receiveCountLabel->setNum(receiveCount);
|
||
|
||
// 记录日志
|
||
if (m_logRecord->isLogging())
|
||
{
|
||
m_logRecord->logReceive("[" + portName + "] " + str.toUpper());
|
||
}
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
// 设置串口参数
|
||
QSerialPort* port = m_serialPorts[portName];
|
||
port->setPortName(portName);
|
||
port->setBaudRate(baudRate);
|
||
port->setDataBits(dataBits);
|
||
port->setParity(parity);
|
||
port->setStopBits(stopBits);
|
||
port->setFlowControl(QSerialPort::NoFlowControl);
|
||
|
||
// 尝试打开串口
|
||
if (port->open(QIODevice::ReadWrite))
|
||
{
|
||
qDebug() << "成功打开串口" << portName << "波特率:" << baudRate;
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
qDebug() << "打开串口" << portName << "失败:" << port->errorString();
|
||
CommonHelper::ShowMessageBoxError(tr("无法打开串口 %1: %2").arg(portName).arg(port->errorString()));
|
||
return false;
|
||
}
|
||
}
|
||
|
||
void MainWindow::closeSerialPortForDevice(const QString& portName)
|
||
{
|
||
if (m_serialPorts.contains(portName))
|
||
{
|
||
QSerialPort* port = m_serialPorts[portName];
|
||
if (port->isOpen())
|
||
{
|
||
port->close();
|
||
}
|
||
}
|
||
}
|
||
|
||
// 添加缺失的基础函数实现
|
||
void MainWindow::initUi()
|
||
{
|
||
// 设置窗体标题栏隐藏
|
||
this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | Qt::WindowMinimizeButtonHint);
|
||
|
||
// 显示在屏幕中间
|
||
CommonHelper::FormInCenter(this);
|
||
|
||
mousePressed = false;
|
||
|
||
//安装事件监听器,让标题栏识别鼠标双击
|
||
ui->lblTitle->installEventFilter(this);
|
||
|
||
FramelessHelper* pHelper = new FramelessHelper(this);
|
||
pHelper->activateOn(this); //激活当前窗体
|
||
pHelper->setTitleHeight(ui->wgtTitleBar->height()); //设置窗体的标题栏高度
|
||
|
||
// 初始化设置下拉框
|
||
ui->stackedWidget->setCurrentIndex(0);
|
||
|
||
ui->settingsGroupBox->hide();
|
||
|
||
// 添加波特率选项
|
||
ui->baudRateComboBox->addItem(QStringLiteral("1200"), 1200);
|
||
ui->baudRateComboBox->addItem(QStringLiteral("2400"), 2400);
|
||
ui->baudRateComboBox->addItem(QStringLiteral("4800"), 4800);
|
||
ui->baudRateComboBox->addItem(QStringLiteral("9600"), 9600);
|
||
ui->baudRateComboBox->addItem(QStringLiteral("19200"), 19200);
|
||
ui->baudRateComboBox->addItem(QStringLiteral("38400"), 38400);
|
||
ui->baudRateComboBox->addItem(QStringLiteral("57600"), 57600);
|
||
ui->baudRateComboBox->addItem(QStringLiteral("115200"), 115200);
|
||
ui->baudRateComboBox->setCurrentIndex(7); // 默认选择115200
|
||
|
||
ui->parityComboBox->addItem(tr("None"), QSerialPort::NoParity);
|
||
ui->parityComboBox->addItem(tr("Even"), QSerialPort::EvenParity);
|
||
ui->parityComboBox->addItem(tr("Odd"), QSerialPort::OddParity);
|
||
|
||
ui->dataBitsComboBox->addItem(QStringLiteral("8"), QSerialPort::Data8);
|
||
ui->dataBitsComboBox->addItem(QStringLiteral("7"), QSerialPort::Data7);
|
||
ui->dataBitsComboBox->addItem(QStringLiteral("6"), QSerialPort::Data6);
|
||
ui->dataBitsComboBox->addItem(QStringLiteral("5"), QSerialPort::Data5);
|
||
ui->dataBitsComboBox->setCurrentIndex(0);
|
||
|
||
ui->stopBitsComboBox->addItem(QStringLiteral("1"), QSerialPort::OneStop);
|
||
ui->stopBitsComboBox->addItem(QStringLiteral("2"), QSerialPort::TwoStop);
|
||
|
||
// 初始化单元表格
|
||
ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||
|
||
// 设置新的表格标题,匹配CSV的13列格式 - 修改时间轴说明
|
||
// 设置新的表格标题,匹配CSV的16列格式 - 添加了设备5
|
||
m_headers = QStringList{"序号", "时间点(S)", "设备1指令", "设备1协议", "设备1通讯",
|
||
"设备2指令", "设备2协议", "设备2通讯", "设备3指令", "设备3协议",
|
||
"设备3通讯", "设备4指令", "设备4协议", "设备4通讯", "设备5指令",
|
||
"设备5协议", "设备5通讯", "设备6指令",
|
||
"设备6协议", "设备6通讯", "设备6主题", "有效", "发送"};
|
||
ui->tableWidget->setColumnCount(COLUMN_MAX);
|
||
ui->tableWidget->setHorizontalHeaderLabels(m_headers);
|
||
|
||
// 设置列宽
|
||
for (int i = 0; i < COLUMN_MAX; ++i)
|
||
{
|
||
ui->tableWidget->setColumnWidth(i, i == 0 ? 60 : (i == 1 ? 80 : (i == COLUMN_VALID ? 60 : (i == COLUMN_SENDBUTTON ? 80 : 120))));
|
||
}
|
||
|
||
// 初始化串口连接图标
|
||
ui->connectInfo->setPixmap(QPixmap(":/skin/image/error.png"));
|
||
ui->connectInfo->setScaledContents(true);
|
||
|
||
// 获取系统日期时间
|
||
getCurrentDate();
|
||
// // 设置样式表
|
||
// QFile file(QString(":/skin/stylesheet/%1.qss").arg(styleStr));
|
||
// file.open(QFile::ReadOnly);
|
||
// QString qss = QLatin1String(file.readAll());
|
||
// qApp->setStyleSheet(qss);
|
||
|
||
// 添加翻译文件
|
||
QTranslator* translator = new QTranslator;
|
||
if (translator->load(":/qt_zh_CN.qm"))
|
||
{
|
||
qApp->installTranslator(translator);
|
||
}
|
||
|
||
// 获取并添加系统可用COM端口
|
||
foreach (const QSerialPortInfo& info, QSerialPortInfo::availablePorts())
|
||
{
|
||
ui->comComboBox->addItem(info.portName());
|
||
}
|
||
|
||
// 初始化日志按钮状态
|
||
ui->stopLogButton->setEnabled(false);
|
||
}
|
||
|
||
void MainWindow::connections()
|
||
{
|
||
// 串口数据接收
|
||
connect(m_serialPort, &QSerialPort::readyRead, this, &MainWindow::readData);
|
||
|
||
// 连接串口按钮
|
||
connect(ui->connectBtn, &QPushButton::clicked, this, &MainWindow::connectCOMButtonSlot);
|
||
|
||
// 发送数据相关 - 修正按钮名称
|
||
// connect(ui->sendDataBtn, &QPushButton::clicked, this, &MainWindow::sendDataSlot);
|
||
// connect(ui->backBtn, &QPushButton::clicked, this, &MainWindow::backSlot);
|
||
// 注释掉不存在的按钮连接,或者根据实际UI文件中的按钮名称进行连接
|
||
|
||
// 表格操作
|
||
// connect(ui->addItemButton, &QPushButton::clicked, this, &MainWindow::addItemSlot);
|
||
connect(ui->removeItemButton, &QPushButton::clicked, this, &MainWindow::removeItemSlot);
|
||
connect(ui->clearAllBtn, &QPushButton::clicked, this, &MainWindow::clearAllSlot);
|
||
|
||
// 文件操作
|
||
connect(ui->loadFileBtn, &QPushButton::clicked, this, &MainWindow::loadFileSlot);
|
||
connect(ui->saveFileBtn, &QPushButton::clicked, this, &MainWindow::saveFileSlot);
|
||
|
||
// 滚动条自动滚动
|
||
connect(ui->sendTextEdit->verticalScrollBar(), &QScrollBar::valueChanged,
|
||
this, &MainWindow::sendTextAutoScrollSlot);
|
||
connect(ui->receiveTextEdit->verticalScrollBar(), &QScrollBar::valueChanged,
|
||
this, &MainWindow::receiveTextAutoScrollSlot);
|
||
|
||
// 同步下拉框
|
||
connect(ui->comComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||
this, &MainWindow::synchronizeComboBoxes);
|
||
connect(ui->NewComcomboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||
this, &MainWindow::synchronizeComboBoxes);
|
||
}
|
||
void MainWindow::updateComSettings()
|
||
{
|
||
// 获取串口名称 - 优先使用主界面的选择
|
||
QString selectedPort;
|
||
if (!ui->NewComcomboBox->currentText().isEmpty())
|
||
{
|
||
selectedPort = ui->NewComcomboBox->currentText();
|
||
}
|
||
else if (!ui->comComboBox->currentText().isEmpty())
|
||
{
|
||
selectedPort = ui->comComboBox->currentText();
|
||
}
|
||
else
|
||
{
|
||
CommonHelper::ShowMessageBoxError(tr("请先选择串口!"));
|
||
return;
|
||
}
|
||
|
||
// 提取纯串口名(去掉可能的描述信息)
|
||
if (selectedPort.contains("("))
|
||
{
|
||
currentSettings.name = selectedPort.split("(").first().trimmed();
|
||
}
|
||
else
|
||
{
|
||
currentSettings.name = selectedPort.split(" ").first().trimmed();
|
||
}
|
||
|
||
// 获取波特率
|
||
bool ok;
|
||
int baudRate = ui->baudRateComboBox->currentData().toInt(&ok);
|
||
if (!ok)
|
||
{
|
||
baudRate = ui->baudRateComboBox->currentText().toInt(&ok);
|
||
if (!ok)
|
||
{
|
||
baudRate = 115200; // 默认波特率
|
||
}
|
||
}
|
||
currentSettings.baudRate = baudRate;
|
||
currentSettings.stringBaudRate = QString::number(baudRate);
|
||
|
||
// 获取数据位
|
||
currentSettings.dataBits = static_cast<QSerialPort::DataBits>(
|
||
ui->dataBitsComboBox->itemData(ui->dataBitsComboBox->currentIndex()).toInt());
|
||
currentSettings.stringDataBits = ui->dataBitsComboBox->currentText();
|
||
|
||
// 获取校验位
|
||
currentSettings.parity = static_cast<QSerialPort::Parity>(
|
||
ui->parityComboBox->itemData(ui->parityComboBox->currentIndex()).toInt());
|
||
currentSettings.stringParity = ui->parityComboBox->currentText();
|
||
|
||
// 获取停止位
|
||
currentSettings.stopBits = static_cast<QSerialPort::StopBits>(
|
||
ui->stopBitsComboBox->itemData(ui->stopBitsComboBox->currentIndex()).toInt());
|
||
currentSettings.stringStopBits = ui->stopBitsComboBox->currentText();
|
||
}
|
||
|
||
char MainWindow::ConvertHexChar(char ch)
|
||
{
|
||
if ((ch >= '0') && (ch <= '9'))
|
||
return ch - 0x30;
|
||
else if ((ch >= 'A') && (ch <= 'F'))
|
||
return ch - 'A' + 10;
|
||
else if ((ch >= 'a') && (ch <= 'f'))
|
||
return ch - 'a' + 10;
|
||
else
|
||
return (-1);
|
||
}
|
||
|
||
// QByteArray MainWindow::QString2Hex(QString str)
|
||
// {
|
||
// QByteArray senddata;
|
||
// int hexdata,lowhexdata;
|
||
// int hexdatalen = 0;
|
||
// int len = str.length();
|
||
// senddata.resize(len/2);
|
||
// char lstr,hstr;
|
||
// for(int i=0; i<len; )
|
||
// {
|
||
// hstr=str[i].toLatin1();
|
||
// if(hstr == ' ')
|
||
// {
|
||
// i++;
|
||
// continue;
|
||
// }
|
||
// i++;
|
||
// if(i >= len)
|
||
// break;
|
||
// lstr = str[i].toLatin1();
|
||
// hexdata = ConvertHexChar(hstr);
|
||
// lowhexdata = ConvertHexChar(lstr);
|
||
// if((hexdata == 16) || (lowhexdata == 16))
|
||
// break;
|
||
// else
|
||
// hexdata = hexdata*16+lowhexdata;
|
||
// i++;
|
||
// senddata[hexdatalen] = (char)hexdata;
|
||
// hexdatalen++;
|
||
// }
|
||
// senddata.resize(hexdatalen);
|
||
// return senddata;
|
||
// }
|
||
|
||
QByteArray MainWindow::QString2Hex(QString str)
|
||
{
|
||
QByteArray senddata;
|
||
int hexdata, lowhexdata;
|
||
int hexdatalen = 0;
|
||
int len = str.length();
|
||
|
||
// 预先计算可能的最大容量(假设所有字符都是有效的hex字符)
|
||
senddata.resize((len + 1) / 2);
|
||
|
||
char lstr, hstr;
|
||
for (int i = 0; i < len;)
|
||
{
|
||
hstr = str[i].toLatin1();
|
||
if (hstr == ' ' || hstr == '\t' || hstr == '\r' || hstr == '\n')
|
||
{
|
||
// 跳过所有空白字符
|
||
i++;
|
||
continue;
|
||
}
|
||
|
||
i++;
|
||
if (i >= len)
|
||
break;
|
||
|
||
lstr = str[i].toLatin1();
|
||
hexdata = ConvertHexChar(hstr);
|
||
lowhexdata = ConvertHexChar(lstr);
|
||
|
||
if ((hexdata == -1) || (lowhexdata == -1))
|
||
{
|
||
// 遇到无效的hex字符,跳过这对字符
|
||
i++;
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
hexdata = hexdata * 16 + lowhexdata;
|
||
}
|
||
|
||
i++;
|
||
senddata[hexdatalen] = (char)hexdata;
|
||
hexdatalen++;
|
||
}
|
||
|
||
// 调整到实际使用的大小
|
||
senddata.resize(hexdatalen);
|
||
return senddata;
|
||
}
|
||
|
||
QString MainWindow::ShowHex(QByteArray data)
|
||
{
|
||
QString temp = "";
|
||
QString hex = data.toHex();
|
||
for (int i = 0; i < hex.length(); i += 2)
|
||
{
|
||
temp += hex.mid(i, 2) + " ";
|
||
}
|
||
return temp.toUpper();
|
||
}
|
||
|
||
void MainWindow::getCurrentDate()
|
||
{
|
||
currentDateTime = QDateTime::currentDateTime();
|
||
currentTime = QTime::currentTime();
|
||
|
||
// 根据时间设置样式
|
||
if (currentTime.hour() >= 6 && currentTime.hour() < COLUMN_SENDBUTTON)
|
||
{
|
||
styleStr = "green"; // 白天模式
|
||
}
|
||
else
|
||
{
|
||
styleStr = "dark"; // 夜间模式
|
||
}
|
||
}
|
||
|
||
void MainWindow::setWinterTime()
|
||
{
|
||
styleStr = "green";
|
||
}
|
||
|
||
void MainWindow::setSummerTime()
|
||
{
|
||
styleStr = "green";
|
||
}
|
||
|
||
char MainWindow::xorCheck(QByteArray array)
|
||
{
|
||
char xorData = 0;
|
||
for (int i = 0; i < array.size(); i++)
|
||
{
|
||
xorData ^= array.at(i);
|
||
}
|
||
return xorData;
|
||
}
|
||
|
||
char MainWindow::sumCheck(QByteArray array)
|
||
{
|
||
char sumData = 0;
|
||
for (int i = 0; i < array.size(); i++)
|
||
{
|
||
sumData += array.at(i);
|
||
}
|
||
return sumData;
|
||
}
|
||
|
||
void MainWindow::sendFile()
|
||
{
|
||
if (bSendFile)
|
||
{
|
||
m_lSendPoint = 0;
|
||
bSendFile = false;
|
||
sendFileTimer->start(1);
|
||
}
|
||
}
|
||
|
||
void MainWindow::removeListSame(QStringList* list)
|
||
{
|
||
for (int i = 0; i < list->size(); i++)
|
||
{
|
||
for (int j = i + 1; j < list->size();)
|
||
{
|
||
if (list->at(i) == list->at(j))
|
||
{
|
||
list->removeAt(j);
|
||
}
|
||
else
|
||
{
|
||
j++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void MainWindow::on_pushButton_mqttBtn_clicked()
|
||
{
|
||
QString ip = ui->lineEdit_ip->text();
|
||
QString port = ui->lineEdit_port->text();
|
||
QString ipPort = ip + ":" + port;
|
||
|
||
// mqtt连接
|
||
if (!b_mqtt_connected)
|
||
{
|
||
|
||
if (!ipPort.isEmpty() && ipPort.split(":").size() > 0)
|
||
{
|
||
// 检查此设备是否已经创建和打开
|
||
|
||
if (!ConnectMQTTServer(ipPort, m_mqttClient))
|
||
{
|
||
return;
|
||
}
|
||
b_mqtt_connected = true;
|
||
ui->lineEdit_ip->setDisabled(true);
|
||
ui->lineEdit_port->setDisabled(true);
|
||
ui->lineEdit_topic->setDisabled(true);
|
||
ui->pushButton_mqttBtn->setText("已连接");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
b_mqtt_connected = false;
|
||
DisconnectMQTTServer(ipPort);
|
||
ui->lineEdit_ip->setDisabled(false);
|
||
ui->lineEdit_port->setDisabled(false);
|
||
ui->lineEdit_topic->setDisabled(false);
|
||
ui->pushButton_mqttBtn->setText("连接");
|
||
}
|
||
}
|