#include "EfficiencyScale.h" #include "ui_EfficiencyScale.h" #include #include #include #include #include #include "CustomQwtPlot.h" #include #include #include #include #include #include #include #include #include #include #include "DataCalcProcess/EnergyEfficiencyFit.h" EfficiencyScale::EfficiencyScale(QWidget *parent) : QDialog(parent) , ui(new Ui::EfficiencyScale) { ui->setupUi(this); QHBoxLayout* inflectionLayout = new QHBoxLayout(); QLabel* inflectionLabel = new QLabel(QStringLiteral(u"拐点能量(keV):"), this); QLineEdit* inflectionEdit = new QLineEdit(this); inflectionEdit->setObjectName("lineEdit_inflection_energy"); inflectionEdit->setPlaceholderText("0 = 全段统一拟合"); inflectionLayout->addWidget(inflectionLabel); inflectionLayout->addWidget(inflectionEdit); ui->verticalLayout_16->insertLayout(2, inflectionLayout); this->_plot = new CustomQwtPlot(this); ui->layout_fittingCurve->addWidget(this->_plot); setupPlot(); _rawDataCurve = new QwtPlotCurve(QStringLiteral(u"原始数据")); _rawDataCurve->setStyle(QwtPlotCurve::NoCurve); _rawDataCurve->setSymbol(new QwtSymbol(QwtSymbol::Ellipse, QBrush(Qt::red), QPen(Qt::red), QSize(8, 8))); _rawDataCurve->attach(_plot); _fitCurve = new QwtPlotCurve(QStringLiteral(u"拟合曲线")); _fitCurve->setPen(QPen(Qt::blue, 2)); _fitCurve->attach(_plot); ui->table_scale_data->verticalHeader()->hide(); initComboBoxUi(); // 初始化32个通道数据 for (int i = 1; i <= 32; ++i) { QString channelName = QStringLiteral(u"通道%1").arg(i); m_channelDataMap.insert(channelName, ChannelEfficiencyData()); } m_currentChannel = QStringLiteral(u"通道1"); // 连接通道切换信号 connect(ui->comboBox_channel, SIGNAL(currentIndexChanged(int)), this, SLOT(on_comboBox_channel_currentIndexChanged(int))); // 表格设置 ui->table_scale_data->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); ui->table_scale_data->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked); // 连接表格编辑信号 connect(ui->table_scale_data, SIGNAL(itemChanged(QTableWidgetItem*)), this, SLOT(on_table_scale_data_itemChanged(QTableWidgetItem*))); // 初始化显示 refreshTable(); refreshPlot(); // 加载文件列表 loadAllFilesInTheFolder(); } EfficiencyScale::~EfficiencyScale() { delete ui; } void EfficiencyScale::setupPlot() { _plot->setCanvasBackground(Qt::white); QwtPlotCanvas* canvas = qobject_cast(_plot->canvas()); canvas->setFrameStyle(QFrame::NoFrame); QFont font = this->font(); font.setBold(false); QwtText energy_label = QStringLiteral(u"能量"); energy_label.setFont(font); QwtText count_label = QStringLiteral(u"探测效率"); count_label.setFont(font); _plot->setAxisTitle(QwtPlot::xBottom, energy_label); _plot->setAxisTitle(QwtPlot::yLeft, count_label); // 设置轴自动缩放 _plot->setAxisAutoScale(QwtPlot::xBottom, true); _plot->setAxisAutoScale(QwtPlot::yLeft, true); _plot->enableAxis(QwtPlot::xBottom); _plot->enableAxis(QwtPlot::yLeft); _plot->SetAxisDragScale(QwtPlot::xBottom, true); // 启用鼠标追踪 _plot->canvas()->setMouseTracking(true); } void EfficiencyScale::loadAllFilesInTheFolder() { const QString& energy_scale_dir_path = QDir(qApp->applicationDirPath()).filePath("configure/EfficiencyScale"); QDir dir(energy_scale_dir_path); // 确保目录存在 if (!dir.exists()) { dir.mkpath(energy_scale_dir_path); } QFileInfoList infoList = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); ui->listWidget->clear(); for (const QFileInfo &info : infoList) { QString displayName; if (info.isFile()) { displayName = info.baseName(); } else { displayName = info.fileName(); } QListWidgetItem *item = new QListWidgetItem(displayName); item->setData(Qt::UserRole, info.absoluteFilePath()); ui->listWidget->addItem(item); } connect(ui->listWidget, &QListWidget::itemDoubleClicked, this, &EfficiencyScale::onItemDoubleClicked); } void EfficiencyScale::initComboBoxUi() { ui->comboBox_fit_type->addItem(QStringLiteral(u"一次拟合")); ui->comboBox_fit_type->addItem(QStringLiteral(u"二次拟合")); ui->comboBox_fit_type_1->addItem(QStringLiteral(u"一次拟合")); ui->comboBox_fit_type_1->addItem(QStringLiteral(u"二次拟合")); for(int i = 1;i <= 32; ++i) { QString channelName = QStringLiteral(u"通道%1").arg(i); ui->comboBox_channel->addItem(channelName); } } void EfficiencyScale::clearPlot() { _rawDataCurve->detach(); _fitCurve->detach(); _plot->detachItems(QwtPlotItem::Rtti_PlotCurve, false); _plot->replot(); } double EfficiencyScale::calculateCountRate(double netCount, double liveTime) const { if (liveTime <= 0.0) return 0.0; return netCount / liveTime; // cps: 每秒计数个数 } double EfficiencyScale::calculateEfficiency(double netCount, double liveTime, double activity, double branchRatio) const { // 探测效率 ε = N / (t * A * Pγ) // N: 净计数, t: 活时间, A: 活度, Pγ: 分支比 double denominator = liveTime * activity * branchRatio; if (denominator <= 0.0) return 0.0; return netCount / denominator; } void EfficiencyScale::recalculateAllPoints(QVector& points) const { for (auto& pt : points) { pt.countRate = calculateCountRate(pt.netCount, pt.liveTime); pt.efficiency = calculateEfficiency(pt.netCount, pt.liveTime, pt.activity, pt.branchRatio); } } FitResult EfficiencyScale::polynomialFit(const QVector& points, int degree, double minEnergy, double maxEnergy) const { FitResult result; result.degree = degree; // 筛选能量范围内的有效点 QVector eData, epsData; for (const auto& pt : points) { if (pt.energy >= minEnergy && pt.energy <= maxEnergy && pt.efficiency > 0.0 && pt.energy > 0.0) { eData.append(pt.energy); epsData.append(pt.efficiency); } } int n = eData.size(); if (n <= degree) { result.valid = false; return result; } // 转换为 Armadillo 向量 arma::vec E(n), eps(n); for (int i = 0; i < n; ++i) { E(i) = eData[i]; eps(i) = epsData[i]; } // 调用半经验拟合 try { arma::vec coeffs = EnergyEfficiencyFit::SemiEmpiricalFit(E, eps, degree); // 只取有效阶数的系数(0~degree,共degree+1个) result.coeffs.clear(); for (int i = 0; i <= degree; ++i) { result.coeffs.append(coeffs(i)); } result.valid = true; } catch (...) { result.valid = false; } return result; } double EfficiencyScale::calculateFitEfficiency(double energy, const FitResult& fit) const { if (!fit.valid || energy <= 0.0) return 0.0; double lnE = std::log(energy); double lnEff = 0.0; double xPow = 1.0; for (int i = 0; i < fit.coeffs.size(); ++i) { lnEff += fit.coeffs[i] * xPow; xPow *= lnE; } return std::exp(lnEff); } double EfficiencyScale::calculateTotalEfficiency(double energy, double totalNetCount, double liveTime, double activity, double branchRatio) const { // 谱仪总效率:各通道能峰计数率相加后,按相同公式计算 Q_UNUSED(energy); return calculateEfficiency(totalNetCount, liveTime, activity, branchRatio); } ChannelEfficiencyData& EfficiencyScale::currentChannelData() { return m_channelDataMap[m_currentChannel]; } const ChannelEfficiencyData& EfficiencyScale::currentChannelData() const { return m_channelDataMap[m_currentChannel]; } void EfficiencyScale::refreshTable() { const ChannelEfficiencyData& chData = currentChannelData(); const QVector& points = chData.points; // 临时断开信号避免触发itemChanged disconnect(ui->table_scale_data, SIGNAL(itemChanged(QTableWidgetItem*)), this, SLOT(on_table_scale_data_itemChanged(QTableWidgetItem*))); ui->table_scale_data->setRowCount(points.size()); for (int row = 0; row < points.size(); ++row) { const EfficiencyPoint& pt = points[row]; // 0: 序号(只读) QTableWidgetItem* item0 = new QTableWidgetItem(QString::number(row + 1)); item0->setFlags(item0->flags() & ~Qt::ItemIsEditable); ui->table_scale_data->setItem(row, 0, item0); // 1: 能量(keV) —— 可编辑输入 ui->table_scale_data->setItem(row, 1, new QTableWidgetItem(QString::number(pt.energy, 'f', 2))); // 2: 净计数N —— 可编辑输入 ui->table_scale_data->setItem(row, 2, new QTableWidgetItem(QString::number(pt.netCount, 'f', 0))); // 3: 活时间t(s) —— 可编辑输入 ui->table_scale_data->setItem(row, 3, new QTableWidgetItem(QString::number(pt.liveTime, 'f', 2))); // 4: 活度A(Bq) —— 可编辑输入 ui->table_scale_data->setItem(row, 4, new QTableWidgetItem(QString::number(pt.activity, 'f', 2))); // 5: 分支比Pγ —— 可编辑输入 ui->table_scale_data->setItem(row, 5, new QTableWidgetItem(QString::number(pt.branchRatio, 'f', 4))); // 6: 净计数率(cps) —— 计算值 QTableWidgetItem* item6 = new QTableWidgetItem(QString::number(pt.countRate, 'f', 4)); item6->setFlags(item6->flags() & ~Qt::ItemIsEditable); ui->table_scale_data->setItem(row, 6, item6); // 7: 探测效率ε —— 计算值 QTableWidgetItem* item7 = new QTableWidgetItem(QString::number(pt.efficiency, 'f', 8)); item7->setFlags(item7->flags() & ~Qt::ItemIsEditable); ui->table_scale_data->setItem(row, 7, item7); // 8: 拟合效率 —— 拟合后计算 QTableWidgetItem* item8; if (pt.fitEfficiency > 0.0) { item8 = new QTableWidgetItem(QString::number(pt.fitEfficiency, 'f', 8)); } else { item8 = new QTableWidgetItem("-"); } item8->setFlags(item8->flags() & ~Qt::ItemIsEditable); ui->table_scale_data->setItem(row, 8, item8); // 9: 误差(%) —— 拟合后计算 QTableWidgetItem* item9; if (pt.error > 0.0) { item9 = new QTableWidgetItem(QString::number(pt.error, 'f', 4) + "%"); } else { item9 = new QTableWidgetItem("-"); } item9->setFlags(item9->flags() & ~Qt::ItemIsEditable); ui->table_scale_data->setItem(row, 9, item9); // 10: 刻度日期 —— 可编辑 ui->table_scale_data->setItem(row, 10, new QTableWidgetItem(pt.scaleDate)); } // 重新连接信号 connect(ui->table_scale_data, SIGNAL(itemChanged(QTableWidgetItem*)), this, SLOT(on_table_scale_data_itemChanged(QTableWidgetItem*))); } // 表格单元格编辑后更新数据并重算 void EfficiencyScale::on_table_scale_data_itemChanged(QTableWidgetItem* item) { int row = item->row(); int col = item->column(); ChannelEfficiencyData& chData = currentChannelData(); if (row >= chData.points.size()) return; EfficiencyPoint& pt = chData.points[row]; bool ok = false; double value = item->text().toDouble(&ok); switch (col) { case 1: // 能量 if (ok) pt.energy = value; break; case 2: // 净计数N if (ok) pt.netCount = value; break; case 3: // 活时间t if (ok) pt.liveTime = value; break; case 4: // 活度A if (ok) pt.activity = value; break; case 5: // 分支比Pγ if (ok) pt.branchRatio = value; break; case 10: // 刻度日期 pt.scaleDate = item->text(); return; // 日期不需要重算 default: return; // 其他列是只读计算列,不处理 } // 修改了输入参数,重新计算计数率和效率 recalculateAllPoints(chData.points); // 刷新表格的计算列(避免递归,直接更新指定单元格) disconnect(ui->table_scale_data, SIGNAL(itemChanged(QTableWidgetItem*)), this, SLOT(on_table_scale_data_itemChanged(QTableWidgetItem*))); ui->table_scale_data->item(row, 6)->setText(QString::number(pt.countRate, 'f', 4)); ui->table_scale_data->item(row, 7)->setText(QString::number(pt.efficiency, 'e', 6)); connect(ui->table_scale_data, SIGNAL(itemChanged(QTableWidgetItem*)), this, SLOT(on_table_scale_data_itemChanged(QTableWidgetItem*))); refreshPlot(); } QVector EfficiencyScale::generateFitCurvePoints(const FitResult& highFit, const FitResult& lowFit, double inflectionEnergy, int sampleCount) const { QVector curvePoints; const ChannelEfficiencyData& chData = currentChannelData(); if (chData.points.isEmpty()) return curvePoints; // 找能量范围 double minE = chData.points.first().energy; double maxE = chData.points.first().energy; for (const auto& pt : chData.points) { minE = qMin(minE, pt.energy); maxE = qMax(maxE, pt.energy); } if (minE <= 0 || maxE <= 0) return curvePoints; // 采样 double logMin = std::log(minE); double logMax = std::log(maxE); double step = (logMax - logMin) / sampleCount; for (int i = 0; i <= sampleCount; ++i) { double logE = logMin + i * step; double energy = std::exp(logE); double eff = 0.0; if (inflectionEnergy > 0 && energy < inflectionEnergy) { // 拐点以下用低能拟合 if (lowFit.valid) { eff = calculateFitEfficiency(energy, lowFit); } } else { // 拐点以上用高能拟合 if (highFit.valid) { eff = calculateFitEfficiency(energy, highFit); } else if (lowFit.valid) { eff = calculateFitEfficiency(energy, lowFit); } } if (eff > 0.0) { curvePoints.append(QPointF(energy, eff)); } } return curvePoints; } void EfficiencyScale::refreshPlot() { if (!_plot || !_rawDataCurve || !_fitCurve) return; const ChannelEfficiencyData& chData = currentChannelData(); // 原始数据散点 QVector rawPoints; for (const auto& pt : chData.points) { if (pt.efficiency > 0.0) { rawPoints.append(QPointF(pt.energy, pt.efficiency)); } } _rawDataCurve->setSamples(rawPoints); // 拟合曲线 QVector fitPoints = generateFitCurvePoints( chData.highFit, chData.lowFit, chData.inflectionEnergy); _fitCurve->setSamples(fitPoints); _plot->replot(); } void EfficiencyScale::on_pBtn_Add_clicked() { ChannelEfficiencyData& chData = currentChannelData(); EfficiencyPoint newPoint; newPoint.scaleDate = QDateTime::currentDateTime().toString("yyyy-MM-dd"); // 默认值 newPoint.energy = 0.0; newPoint.netCount = 0.0; newPoint.liveTime = 1.0; newPoint.activity = 1.0; newPoint.branchRatio = 1.0; chData.points.append(newPoint); recalculateAllPoints(chData.points); refreshTable(); refreshPlot(); } void EfficiencyScale::on_pBtn_Delete_clicked() { int currentRow = ui->table_scale_data->currentRow(); if (currentRow < 0) { QMessageBox::warning(this, QStringLiteral(u"提示"), QStringLiteral(u"请先选中要删除的刻度点")); return; } ChannelEfficiencyData& chData = currentChannelData(); if (currentRow >= chData.points.size()) return; chData.points.removeAt(currentRow); recalculateAllPoints(chData.points); refreshTable(); refreshPlot(); } void EfficiencyScale::on_pBtn_fitting_4_clicked() { // 拐点以上拟合 ChannelEfficiencyData& chData = currentChannelData(); QLineEdit* inflectionEdit = findChild("lineEdit_inflection_energy"); if (inflectionEdit) { bool ok = false; double val = inflectionEdit->text().toDouble(&ok); chData.inflectionEnergy = (ok && val > 0.0) ? val : 0.0; } if (chData.points.size() < 2) { QMessageBox::warning(this, QStringLiteral(u"提示"), QStringLiteral(u"至少需要2个刻度点才能进行拟合")); return; } int degree = ui->comboBox_fit_type->currentIndex() + 1; // 1或2 double inflectionE = chData.inflectionEnergy; // 如果没有设置拐点,默认全部用高能拟合 double minE = inflectionE > 0 ? inflectionE : 0.0; double maxE = 1e9; // 足够大 chData.highFit = polynomialFit(chData.points, degree, minE, maxE); if (!chData.highFit.valid) { QMessageBox::critical(this, QStringLiteral(u"错误"), QStringLiteral(u"拟合失败,请检查数据")); return; } // 更新各点的拟合效率和误差 for (auto& pt : chData.points) { if (inflectionE <= 0 || pt.energy >= inflectionE) { pt.fitEfficiency = calculateFitEfficiency(pt.energy, chData.highFit); if (pt.efficiency > 0.0) { pt.error = std::abs(pt.fitEfficiency - pt.efficiency) / pt.efficiency * 100.0; } } } refreshTable(); refreshPlot(); } void EfficiencyScale::on_pBtn_fitting_3_clicked() { // 拐点以下拟合 ChannelEfficiencyData& chData = currentChannelData(); QLineEdit* inflectionEdit = findChild("lineEdit_inflection_energy"); if (inflectionEdit) { bool ok = false; double val = inflectionEdit->text().toDouble(&ok); chData.inflectionEnergy = (ok && val > 0.0) ? val : 0.0; } if (chData.points.size() < 2) { QMessageBox::warning(this, QStringLiteral(u"提示"), QStringLiteral(u"至少需要2个刻度点才能进行拟合")); return; } int degree = ui->comboBox_fit_type_1->currentIndex() + 1; // 1或2 double inflectionE = chData.inflectionEnergy; double minE = 0.0; double maxE = inflectionE > 0 ? inflectionE : 1e9; chData.lowFit = polynomialFit(chData.points, degree, minE, maxE); if (!chData.lowFit.valid) { QMessageBox::critical(this, QStringLiteral(u"错误"), QStringLiteral(u"拟合失败,请检查数据")); return; } // 更新各点的拟合效率和误差 for (auto& pt : chData.points) { if (inflectionE <= 0 || pt.energy < inflectionE) { pt.fitEfficiency = calculateFitEfficiency(pt.energy, chData.lowFit); if (pt.efficiency > 0.0) { pt.error = std::abs(pt.fitEfficiency - pt.efficiency) / pt.efficiency * 100.0; } } } refreshTable(); refreshPlot(); } void EfficiencyScale::on_comboBox_channel_currentIndexChanged(int index) { Q_UNUSED(index); QLineEdit* inflectionEdit = findChild("lineEdit_inflection_energy"); if (inflectionEdit) { const ChannelEfficiencyData& chData = currentChannelData(); if (chData.inflectionEnergy > 0.0) { inflectionEdit->setText(QString::number(chData.inflectionEnergy, 'f', 2)); } else { inflectionEdit->clear(); } } m_currentChannel = ui->comboBox_channel->currentText(); refreshTable(); refreshPlot(); } bool EfficiencyScale::saveToJsonFile(const QString& filePath) const { QJsonObject rootObj; rootObj["scaleName"] = ui->lineEdit_name->text(); rootObj["description"] = ui->plainTextEdit_description_3->toPlainText(); rootObj["currentChannel"] = m_currentChannel; QJsonArray channelsArray; for (auto it = m_channelDataMap.constBegin(); it != m_channelDataMap.constEnd(); ++it) { QJsonObject chObj; chObj["channelName"] = it.key(); chObj["inflectionEnergy"] = it.value().inflectionEnergy; // 刻度点 QJsonArray pointsArray; for (const auto& pt : it.value().points) { QJsonObject ptObj; ptObj["energy"] = pt.energy; ptObj["netCount"] = pt.netCount; ptObj["liveTime"] = pt.liveTime; ptObj["activity"] = pt.activity; ptObj["branchRatio"] = pt.branchRatio; ptObj["countRate"] = pt.countRate; ptObj["efficiency"] = pt.efficiency; ptObj["fitEfficiency"] = pt.fitEfficiency; ptObj["error"] = pt.error; ptObj["scaleDate"] = pt.scaleDate; pointsArray.append(ptObj); } chObj["points"] = pointsArray; // 高能拟合 QJsonObject highFitObj; highFitObj["valid"] = it.value().highFit.valid; highFitObj["degree"] = it.value().highFit.degree; QJsonArray highCoeffs; for (double c : it.value().highFit.coeffs) highCoeffs.append(c); highFitObj["coeffs"] = highCoeffs; chObj["highFit"] = highFitObj; // 低能拟合 QJsonObject lowFitObj; lowFitObj["valid"] = it.value().lowFit.valid; lowFitObj["degree"] = it.value().lowFit.degree; QJsonArray lowCoeffs; for (double c : it.value().lowFit.coeffs) lowCoeffs.append(c); lowFitObj["coeffs"] = lowCoeffs; chObj["lowFit"] = lowFitObj; channelsArray.append(chObj); } rootObj["channels"] = channelsArray; QJsonDocument doc(rootObj); QFile file(filePath); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return false; } file.write(doc.toJson()); file.close(); return true; } bool EfficiencyScale::loadFromJsonFile(const QString& filePath) { QFile file(filePath); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { return false; } QByteArray data = file.readAll(); file.close(); QJsonDocument doc = QJsonDocument::fromJson(data); if (!doc.isObject()) return false; QJsonObject rootObj = doc.object(); ui->lineEdit_name->setText(rootObj["scaleName"].toString()); ui->plainTextEdit_description_3->setPlainText(rootObj["description"].toString()); QJsonArray channelsArray = rootObj["channels"].toArray(); for (const auto& chVal : channelsArray) { QJsonObject chObj = chVal.toObject(); QString chName = chObj["channelName"].toString(); if (!m_channelDataMap.contains(chName)) continue; ChannelEfficiencyData chData; chData.inflectionEnergy = chObj["inflectionEnergy"].toDouble(); // 刻度点 QJsonArray pointsArray = chObj["points"].toArray(); for (const auto& ptVal : pointsArray) { QJsonObject ptObj = ptVal.toObject(); EfficiencyPoint pt; pt.energy = ptObj["energy"].toDouble(); pt.netCount = ptObj["netCount"].toDouble(); pt.liveTime = ptObj["liveTime"].toDouble(); pt.activity = ptObj["activity"].toDouble(); pt.branchRatio = ptObj["branchRatio"].toDouble(); pt.countRate = ptObj["countRate"].toDouble(); pt.efficiency = ptObj["efficiency"].toDouble(); pt.fitEfficiency = ptObj["fitEfficiency"].toDouble(); pt.error = ptObj["error"].toDouble(); pt.scaleDate = ptObj["scaleDate"].toString(); chData.points.append(pt); } // 高能拟合 QJsonObject highFitObj = chObj["highFit"].toObject(); chData.highFit.valid = highFitObj["valid"].toBool(); chData.highFit.degree = highFitObj["degree"].toInt(); QJsonArray highCoeffs = highFitObj["coeffs"].toArray(); for (const auto& c : highCoeffs) chData.highFit.coeffs.append(c.toDouble()); // 低能拟合 QJsonObject lowFitObj = chObj["lowFit"].toObject(); chData.lowFit.valid = lowFitObj["valid"].toBool(); chData.lowFit.degree = lowFitObj["degree"].toInt(); QJsonArray lowCoeffs = lowFitObj["coeffs"].toArray(); for (const auto& c : lowCoeffs) chData.lowFit.coeffs.append(c.toDouble()); m_channelDataMap[chName] = chData; } m_currentFilePath = filePath; refreshTable(); refreshPlot(); return true; } void EfficiencyScale::onItemDoubleClicked(QListWidgetItem *item) { if (!item) return; QString filePath = item->data(Qt::UserRole).toString(); if (filePath.isEmpty()) return; QFileInfo fileInfo(filePath); if (!fileInfo.isFile()) return; if (loadFromJsonFile(filePath)) { ui->lineEdit_name->setText(item->text()); QMessageBox::information(this, QStringLiteral(u"成功"), QStringLiteral(u"加载成功:%1").arg(item->text())); } else { QMessageBox::critical(this, QStringLiteral(u"错误"), QStringLiteral(u"加载失败:文件格式不正确")); } } void EfficiencyScale::on_pBtn_Save_clicked() { if (m_currentFilePath.isEmpty()) { on_pBtn_SaveAs_clicked(); return; } if (saveToJsonFile(m_currentFilePath)) { QMessageBox::information(this, QStringLiteral(u"成功"), QStringLiteral(u"保存成功")); } else { QMessageBox::critical(this, QStringLiteral(u"错误"), QStringLiteral(u"保存失败")); } } void EfficiencyScale::on_pBtn_SaveAs_clicked() { QString defaultDir = QDir(qApp->applicationDirPath()).filePath("configure/EfficiencyScale"); QString fileName = QFileDialog::getSaveFileName(this, QStringLiteral(u"另存为"), defaultDir, QStringLiteral(u"效率刻度文件 (*.json)")); if (fileName.isEmpty()) return; if (saveToJsonFile(fileName)) { m_currentFilePath = fileName; loadAllFilesInTheFolder(); // 刷新列表 QMessageBox::information(this, QStringLiteral(u"成功"), QStringLiteral(u"保存成功")); } else { QMessageBox::critical(this, QStringLiteral(u"错误"), QStringLiteral(u"保存失败")); } } void EfficiencyScale::on_pBtn_Add_File_clicked() { QString defaultDir = QDir(qApp->applicationDirPath()).filePath("configure/EfficiencyScale"); QString fileName = QFileDialog::getSaveFileName(this, QStringLiteral(u"新建效率刻度文件"), defaultDir, QStringLiteral(u"效率刻度文件 (*.json)")); if (fileName.isEmpty()) return; // 确保后缀 if (!fileName.endsWith(".json", Qt::CaseInsensitive)) { fileName += ".json"; } // 清空当前数据,生成空白刻度 m_scaleName = QFileInfo(fileName).completeBaseName(); m_description.clear(); m_currentChannel = QStringLiteral(u"通道1"); for (auto it = m_channelDataMap.begin(); it != m_channelDataMap.end(); ++it) { it.value().points.clear(); it.value().highFit = FitResult(); it.value().lowFit = FitResult(); it.value().inflectionEnergy = 0.0; } // 保存空白文件 if (saveToJsonFile(fileName)) { m_currentFilePath = fileName; ui->lineEdit_name->setText(m_scaleName); ui->plainTextEdit_description_3->setPlainText(m_description); loadAllFilesInTheFolder(); refreshTable(); refreshPlot(); QMessageBox::information(this, QStringLiteral(u"成功"), QStringLiteral(u"新建成功")); } else { QMessageBox::critical(this, QStringLiteral(u"错误"), QStringLiteral(u"新建失败")); } } void EfficiencyScale::on_pBtn_Delete_File_clicked() { QListWidgetItem* selectedItem = ui->listWidget->currentItem(); if (!selectedItem) { QMessageBox::warning(this, QStringLiteral(u"提示"), QStringLiteral(u"请先选中要删除的文件/文件夹")); return; } QString filePath = selectedItem->data(Qt::UserRole).toString(); if (filePath.isEmpty()) { QMessageBox::warning(this, QStringLiteral(u"错误"), QStringLiteral(u"无法获取文件路径")); return; } QMessageBox::StandardButton ret = QMessageBox::question(this, QStringLiteral(u"确认删除"), QStringLiteral(u"是否确定删除%1?\n删除后无法恢复!").arg(selectedItem->text()), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (ret != QMessageBox::Yes) { return; } bool isDeleted = false; QFileInfo fileInfo(filePath); if (fileInfo.isFile()) { QFile file(filePath); isDeleted = file.remove(); } if (isDeleted) { loadAllFilesInTheFolder(); if (m_currentFilePath == filePath) { m_currentFilePath.clear(); ui->lineEdit_name->clear(); ui->table_scale_data->setRowCount(0); clearPlot(); _plot->replot(); } QMessageBox::information(this, QStringLiteral(u"成功"), QStringLiteral(u"删除成功")); } else { QMessageBox::critical(this, QStringLiteral(u"错误"), QStringLiteral(u"删除失败:%1").arg(filePath)); } }