1121 lines
41 KiB
C++
1121 lines
41 KiB
C++
#include "EnergyScaleForm.h"
|
||
#include "ui_EnergyScaleForm.h"
|
||
#include <QDir>
|
||
#include <QJsonDocument>
|
||
#include <QJsonObject>
|
||
#include <QJsonArray>
|
||
#include <QJsonValue>
|
||
#include <QwtPlotCanvas>
|
||
#include <QwtText>
|
||
#include <QwtPlotCurve>
|
||
#include "CustomQwtPlot.h"
|
||
#include "DataCalcProcess/GaussPolyCoe.h"
|
||
#include "DataCalcProcess/MathModelDefine.h"
|
||
#include "DataCalcProcess/NolinearLeastSquaresCurveFit.h"
|
||
#include <QDebug>
|
||
#include <QDialog>
|
||
#include <QMessageBox>
|
||
#include <QInputDialog>
|
||
#include <QFileDialog>
|
||
|
||
|
||
EnergyScaleForm::EnergyScaleForm(QWidget *parent)
|
||
: MeasureAnalysisView(parent)
|
||
, ui(new Ui::EnergyScaleForm)
|
||
, _plot(nullptr)
|
||
, _rawDataCurve(nullptr)
|
||
, _fitCurve(nullptr)
|
||
, _rawDataSymbol(nullptr)
|
||
, m_isLoadingTable(false)
|
||
{
|
||
ui->setupUi(this);
|
||
this->_plot = new CustomQwtPlot(this);
|
||
ui->layout_fittingCurve->addWidget(this->_plot);
|
||
_rawDataCurve = new QwtPlotCurve("原始数据");
|
||
_fitCurve = new QwtPlotCurve("拟合曲线");
|
||
_rawDataSymbol = new QwtSymbol(QwtSymbol::Ellipse);
|
||
_rawDataSymbol->setSize(8);
|
||
_rawDataSymbol->setBrush(Qt::red);
|
||
_rawDataSymbol->setPen(QPen(Qt::black, 1));
|
||
setupPlot();
|
||
initComboBoxUi();
|
||
initScaleDataTable();
|
||
loadAllFilesInTheFolder();
|
||
connect(ui->comboBox_channel, &QComboBox::currentTextChanged, this, &EnergyScaleForm::on_comboBox_channel_currentTextChanged);
|
||
connect(ui->comboBox_fit_type, &QComboBox::currentTextChanged,this, &EnergyScaleForm::on_comboBox_fit_type_currentTextChanged);
|
||
connect(ui->tablew_scale_data, &QTableWidget::cellChanged,this, &EnergyScaleForm::on_tablew_scale_data_cellChanged);
|
||
}
|
||
|
||
EnergyScaleForm::~EnergyScaleForm()
|
||
{
|
||
delete ui;
|
||
}
|
||
|
||
void EnergyScaleForm::InitViewWorkspace(const QString &project_name)
|
||
{
|
||
|
||
}
|
||
|
||
void EnergyScaleForm::SetAnalyzeDataFilename(const QMap<QString, QVariant> &data_files_set)
|
||
{
|
||
if (!data_files_set.isEmpty()) {
|
||
const QString& data_name = data_files_set.firstKey();
|
||
const QString& data_filename = data_files_set.first().toString();
|
||
QFileInfo info(data_filename);
|
||
QDir dir = info.dir();
|
||
if (QFileInfo(data_filename).exists()) {
|
||
ui->groupBox_3->hide();
|
||
QFileInfo fileInfo(data_filename);
|
||
QString baseName =QString("[%1]%2").arg(dir.dirName()).arg(fileInfo.baseName());
|
||
ui->lineEdit_name->setText(baseName);
|
||
ui->lineEdit_name->setReadOnly(true);
|
||
ui->groupBox_2->hide();
|
||
ui->pBtn_SaveAs->setText(QStringLiteral(u"保存到系统"));
|
||
m_currentFilePath = data_filename;
|
||
QString errorMsg;
|
||
m_channelList = parseJsonToChannels(data_filename, errorMsg);
|
||
on_comboBox_channel_currentTextChanged(QStringLiteral(u"通道1"));
|
||
}
|
||
}
|
||
}
|
||
|
||
void EnergyScaleForm::setupPlot()
|
||
{
|
||
_plot->setCanvasBackground(Qt::white);
|
||
QwtPlotCanvas* canvas = qobject_cast<QwtPlotCanvas*>(_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 EnergyScaleForm::loadAllFilesInTheFolder()
|
||
{
|
||
const QString& energy_scale_dir_path = QDir(qApp->applicationDirPath()).filePath("configure/EnergyScale");
|
||
QDir dir(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, &EnergyScaleForm::onItemDoubleClicked);
|
||
}
|
||
|
||
QMap<QString, ChannelData> EnergyScaleForm::parseJsonToChannels(const QString &filePath, QString &errorMsg)
|
||
{
|
||
QMap<QString, ChannelData> result;
|
||
errorMsg.clear();
|
||
|
||
QFile file(filePath);
|
||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||
errorMsg = QString("无法打开文件: %1").arg(file.errorString());
|
||
return result;
|
||
}
|
||
|
||
QByteArray data = file.readAll();
|
||
file.close();
|
||
|
||
QJsonParseError parseError;
|
||
QJsonDocument doc = QJsonDocument::fromJson(data, &parseError);
|
||
if (parseError.error != QJsonParseError::NoError) {
|
||
errorMsg = QString("JSON 解析错误: %1").arg(parseError.errorString());
|
||
return result;
|
||
}
|
||
|
||
if (!doc.isObject()) {
|
||
errorMsg = "JSON 根节点不是对象";
|
||
return result;
|
||
}
|
||
|
||
QJsonObject rootObj = doc.object();
|
||
if (rootObj.contains("Remark") && rootObj["Remark"].isString())
|
||
ui->plainTextEdit_description->setPlainText(rootObj["Remark"].toString());
|
||
for (auto it = rootObj.begin(); it != rootObj.end(); ++it) {
|
||
QString channelName = it.key();
|
||
QJsonValue channelVal = it.value();
|
||
if (!channelVal.isObject()) {
|
||
errorMsg += QString("通道 %1 的值不是对象,跳过\n").arg(channelName);
|
||
continue;
|
||
}
|
||
QJsonObject channelObj = channelVal.toObject();
|
||
|
||
ChannelData chData;
|
||
|
||
if (channelObj.contains("EnergyFitDegree") && channelObj["EnergyFitDegree"].isDouble()) {
|
||
chData.energyFitDegree = channelObj["EnergyFitDegree"].toInt();
|
||
} else {
|
||
errorMsg += QString("通道 %1 缺少 EnergyFitDegree 字段\n").arg(channelName);
|
||
continue;
|
||
}
|
||
|
||
if (channelObj.contains("EnergyFitResultCoeffs") && channelObj["EnergyFitResultCoeffs"].isArray()) {
|
||
QJsonArray coeffsArr = channelObj["EnergyFitResultCoeffs"].toArray();
|
||
for (QJsonValue v : coeffsArr) {
|
||
if (v.isDouble())
|
||
chData.energyFitResultCoeffs.append(v.toDouble());
|
||
else
|
||
errorMsg += QString("通道 %1 的 EnergyFitResultCoeffs 包含非数字\n").arg(channelName);
|
||
}
|
||
} else {
|
||
errorMsg += QString("通道 %1 缺少 EnergyFitResultCoeffs 字段\n").arg(channelName);
|
||
}
|
||
|
||
if (channelObj.contains("FitData") && channelObj["FitData"].isArray()) {
|
||
QJsonArray fitDataArr = channelObj["FitData"].toArray();
|
||
for (QJsonValue rowVal : fitDataArr) {
|
||
if (!rowVal.isArray()) {
|
||
errorMsg += QString("通道 %1 的 FitData 行不是数组\n").arg(channelName);
|
||
continue;
|
||
}
|
||
QJsonArray rowArr = rowVal.toArray();
|
||
if (rowArr.size() != 7) {
|
||
errorMsg += QString("通道 %1 的 FitData 行长度不为 7(实际 %2)\n")
|
||
.arg(channelName).arg(rowArr.size());
|
||
continue;
|
||
}
|
||
FitDataRow row;
|
||
row.daoSite = rowArr[0].toDouble();
|
||
row.energy = rowArr[1].toDouble();
|
||
row.fittingEnergy = rowArr[2].toDouble();
|
||
row.energyFittingDeviation = rowArr[3].toDouble();
|
||
row.resolution = rowArr[4].toDouble();
|
||
row.fitResolution = rowArr[5].toDouble();
|
||
row.resolutionFittingDeviation = rowArr[6].toDouble();
|
||
chData.fitData.append(row);
|
||
}
|
||
} else {
|
||
errorMsg += QString("通道 %1 缺少 FitData 字段\n").arg(channelName);
|
||
}
|
||
|
||
if (channelObj.contains("FwhmFitResultCoeffs") && channelObj["FwhmFitResultCoeffs"].isArray()) {
|
||
QJsonArray fwhmArr = channelObj["FwhmFitResultCoeffs"].toArray();
|
||
for (QJsonValue v : fwhmArr) {
|
||
if (v.isDouble())
|
||
chData.fwhmFitResultCoeffs.append(v.toDouble());
|
||
else
|
||
errorMsg += QString("通道 %1 的 FwhmFitResultCoeffs 包含非数字\n").arg(channelName);
|
||
}
|
||
} else {
|
||
errorMsg += QString("通道 %1 缺少 FwhmFitResultCoeffs 字段\n").arg(channelName);
|
||
}
|
||
|
||
result.insert(channelName, chData);
|
||
}
|
||
|
||
if (result.isEmpty() && errorMsg.isEmpty())
|
||
errorMsg = "未找到任何通道数据。";
|
||
|
||
return result;
|
||
}
|
||
|
||
void EnergyScaleForm::initComboBoxUi()
|
||
{
|
||
ui->comboBox_fit_type->addItem(QStringLiteral(u"一次拟合"));
|
||
ui->comboBox_fit_type->addItem(QStringLiteral(u"二次拟合"));
|
||
for(int i = 1;i <= 32; ++i)
|
||
{
|
||
QString channelName = QStringLiteral(u"通道%1").arg(i);
|
||
ui->comboBox_channel->addItem(channelName);
|
||
if (!m_channelList.contains(channelName)) {
|
||
ChannelData emptyData;
|
||
emptyData.energyFitDegree = 1;
|
||
m_channelList.insert(channelName, emptyData);
|
||
}
|
||
}
|
||
}
|
||
|
||
void EnergyScaleForm::initScaleDataTable()
|
||
{
|
||
QTableWidget* table = ui->tablew_scale_data;
|
||
table->setColumnCount(7);
|
||
// 设置表格列名
|
||
QStringList headers = {
|
||
"道址", "能量", "拟合能量", "能量拟合偏差",
|
||
"分辨率", "拟合分辨率", "分辨率拟合偏差"
|
||
};
|
||
table->setHorizontalHeaderLabels(headers);
|
||
table->setEditTriggers(QTableWidget::DoubleClicked | QTableWidget::EditKeyPressed);
|
||
table->setSelectionBehavior(QTableWidget::SelectRows); // 整行选中
|
||
table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
||
}
|
||
|
||
void EnergyScaleForm::showChannelData(const QString channelName)
|
||
{
|
||
if (!m_channelList.contains(channelName)) {
|
||
return;
|
||
}
|
||
|
||
m_isLoadingTable = true; // 防止触发cellChanged
|
||
ui->tablew_scale_data->setRowCount(0);
|
||
|
||
const ChannelData& chData = m_channelList[channelName];
|
||
|
||
switch (chData.energyFitDegree) {
|
||
case 1:
|
||
{
|
||
ui->comboBox_fit_type->setCurrentIndex(0);
|
||
ui->label_fit_type_text->setText(QStringLiteral(u"y = a + bx"));
|
||
QString coefficient = QStringLiteral(u"a = %1 , b = %2").arg(chData.energyFitResultCoeffs.at(0)).arg(chData.energyFitResultCoeffs.at(1));
|
||
ui->label_fit_result->setText(coefficient);
|
||
} break;
|
||
case 2:
|
||
ui->comboBox_fit_type->setCurrentIndex(1);
|
||
ui->label_fit_type_text->setText(QStringLiteral(u"y = a + bx + c*x^2"));
|
||
QString coefficient = QStringLiteral(u"a = %1 , b = %2, c = %3").arg(chData.energyFitResultCoeffs.at(0)).arg(chData.energyFitResultCoeffs.at(1)).arg(chData.energyFitResultCoeffs.at(2));
|
||
ui->label_fit_result->setText(coefficient);
|
||
break;
|
||
}
|
||
QString energyCoeffsStr;
|
||
for (int i = 0; i < chData.energyFitResultCoeffs.size(); ++i) {
|
||
energyCoeffsStr += QString("系数%1: %2 ").arg(i+1).arg(chData.energyFitResultCoeffs[i], 0, 'f', 6);
|
||
}
|
||
QTableWidget* table = ui->tablew_scale_data;
|
||
table->setRowCount(chData.fitData.size());
|
||
for (int row = 0; row < chData.fitData.size(); ++row) {
|
||
const FitDataRow& fitRow = chData.fitData[row];
|
||
table->setItem(row, 0, new QTableWidgetItem(QString::number(fitRow.daoSite, 'f', 3)));
|
||
table->setItem(row, 1, new QTableWidgetItem(QString::number(fitRow.energy, 'f', 3)));
|
||
table->setItem(row, 2, new QTableWidgetItem(QString::number(fitRow.fittingEnergy, 'f', 3)));
|
||
table->setItem(row, 3, new QTableWidgetItem(QString::number(fitRow.energyFittingDeviation, 'f', 3)));
|
||
table->setItem(row, 4, new QTableWidgetItem(QString::number(fitRow.resolution, 'f', 3)));
|
||
table->setItem(row, 5, new QTableWidgetItem(QString::number(fitRow.fitResolution, 'f', 3)));
|
||
table->setItem(row, 6, new QTableWidgetItem(QString::number(fitRow.resolutionFittingDeviation, 'f', 3)));
|
||
|
||
for (int col = 0; col < 7; ++col) {
|
||
Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
|
||
if (col == 0 || col == 1 || col == 4) {
|
||
flags |= Qt::ItemIsEditable;
|
||
}
|
||
table->item(row, col)->setFlags(flags);
|
||
}
|
||
}
|
||
m_isLoadingTable = false;
|
||
}
|
||
|
||
void EnergyScaleForm::showCurve()
|
||
{
|
||
clearPlot();
|
||
|
||
QString channelName = ui->comboBox_channel->currentText();
|
||
if (!m_channelList.contains(channelName))
|
||
{
|
||
_plot->replot();
|
||
return;
|
||
}
|
||
const ChannelData &chData = m_channelList[channelName];
|
||
if (chData.fitData.isEmpty()) return;
|
||
|
||
QVector<double> xRaw, yRaw;
|
||
double xMin = 0;
|
||
double xMax = 4096;
|
||
|
||
for (const FitDataRow &row : chData.fitData) {
|
||
xRaw.append(row.daoSite);
|
||
yRaw.append(row.energy);
|
||
}
|
||
_rawDataCurve->setSamples(xRaw, yRaw);
|
||
_rawDataCurve->setSymbol(_rawDataSymbol);
|
||
_rawDataCurve->setStyle(QwtPlotCurve::NoCurve);
|
||
_rawDataCurve->attach(_plot);
|
||
|
||
if (!chData.energyFitResultCoeffs.isEmpty()) {
|
||
QVector<QPointF> fitPoints = generateFitCurvePoints(chData);
|
||
_fitCurve->setSamples(fitPoints);
|
||
_fitCurve->setPen(QPen(Qt::blue, 2)); // 拟合曲线用蓝色粗线
|
||
_fitCurve->setStyle(QwtPlotCurve::Lines);
|
||
_fitCurve->attach(_plot);
|
||
}
|
||
|
||
_plot->replot();
|
||
}
|
||
|
||
void EnergyScaleForm::clearPlot()
|
||
{
|
||
_rawDataCurve->detach();
|
||
_fitCurve->detach();
|
||
_plot->detachItems(QwtPlotItem::Rtti_PlotCurve, false);
|
||
_plot->replot();
|
||
|
||
}
|
||
|
||
QVector<QPointF> EnergyScaleForm::generateFitCurvePoints(const ChannelData &chData)
|
||
{
|
||
int pointCount = 4096;
|
||
QVector<QPointF> points;
|
||
if (chData.energyFitResultCoeffs.isEmpty()) return points;
|
||
|
||
for (int i = 0; i < pointCount; ++i) {
|
||
double y = 0.0;
|
||
switch (chData.energyFitDegree) {
|
||
case 1: // 一次拟合:y = a + b*x
|
||
y = LinearFunction(i,chData.energyFitResultCoeffs[0],chData.energyFitResultCoeffs[1]);
|
||
break;
|
||
case 2: // 二次拟合:y = a + b*x + c*x²
|
||
if (chData.energyFitResultCoeffs.size() >= 3) {
|
||
y = QuadraticPolynomial(i,chData.energyFitResultCoeffs[0],chData.energyFitResultCoeffs[1],chData.energyFitResultCoeffs[2]);
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
points.append(QPointF(i, y));
|
||
}
|
||
return points;
|
||
}
|
||
|
||
QVector<QPointF> EnergyScaleForm::generateFitCurvePoints(const double a, const double b, const double c)
|
||
{
|
||
int pointCount = 4096;
|
||
QVector<QPointF> points;
|
||
// if (chData.energyFitResultCoeffs.isEmpty()) return points;
|
||
|
||
for (int i = 0; i < pointCount; ++i) {
|
||
double y = 0.0;
|
||
switch (ui->comboBox_fit_type->currentIndex() + 1) {
|
||
case 1: y = LinearFunction(i,a,b); ;break;
|
||
case 2: y = QuadraticPolynomial(i,a,b,c);break;
|
||
}
|
||
points.append(QPointF(i, y));
|
||
}
|
||
return points;
|
||
}
|
||
|
||
void EnergyScaleForm::calculateFitValues(ChannelData &chData)
|
||
{
|
||
if (chData.fitData.isEmpty())
|
||
return;
|
||
|
||
if (!chData.energyFitResultCoeffs.isEmpty()) {
|
||
for (auto &row : chData.fitData) {
|
||
double x = row.daoSite;
|
||
double fitE = 0.0;
|
||
|
||
if (chData.energyFitDegree == 1 && chData.energyFitResultCoeffs.size() >= 2) {
|
||
fitE = LinearFunction(x,chData.energyFitResultCoeffs[0],chData.energyFitResultCoeffs[1]);
|
||
}
|
||
else if (chData.energyFitDegree == 2 && chData.energyFitResultCoeffs.size() >= 3) {
|
||
fitE = QuadraticPolynomial(x,chData.energyFitResultCoeffs[0],chData.energyFitResultCoeffs[1],chData.energyFitResultCoeffs[2]);
|
||
}
|
||
|
||
row.fittingEnergy = fitE;
|
||
row.energyFittingDeviation = row.energy - fitE;
|
||
}
|
||
}
|
||
|
||
if (chData.fwhmFitResultCoeffs.size() >= 2)
|
||
{
|
||
arma::vec p(2);
|
||
p(0) = chData.fwhmFitResultCoeffs[0]; // k
|
||
p(1) = chData.fwhmFitResultCoeffs[1]; // c
|
||
|
||
for (auto &row : chData.fitData) {
|
||
double E = row.fittingEnergy;
|
||
if (E <= 0) {
|
||
row.fitResolution = 0.0;
|
||
row.resolutionFittingDeviation = 0.0;
|
||
continue;
|
||
}
|
||
double fitFwhm = FwhmModel(E, p);
|
||
|
||
row.fitResolution = fitFwhm;
|
||
row.resolutionFittingDeviation = row.resolution - fitFwhm;
|
||
}
|
||
}
|
||
else {
|
||
// 没有分辨率参数就清空
|
||
for (auto &row : chData.fitData) {
|
||
row.fitResolution = 0.0;
|
||
row.resolutionFittingDeviation = 0.0;
|
||
}
|
||
}
|
||
}
|
||
|
||
bool EnergyScaleForm::fitFwhmModel(ChannelData &chData)
|
||
{
|
||
std::vector<double> E_list, fwhm_list;
|
||
for (const auto& row : chData.fitData) {
|
||
if (row.fittingEnergy > 0 && row.resolution > 0) {
|
||
E_list.push_back(row.fittingEnergy);
|
||
fwhm_list.push_back(row.resolution);
|
||
}
|
||
}
|
||
if (E_list.size() < 2) {
|
||
return false;
|
||
}
|
||
arma::vec E(E_list.data(), E_list.size());
|
||
arma::vec FWHM(fwhm_list.data(), fwhm_list.size());
|
||
|
||
arma::vec params = NolinearLeastSquaresCurveFit::Lsqcurvefit(FwhmModel,E,FWHM, { 1.0, 1.0 });
|
||
chData.fwhmFitResultCoeffs.clear();
|
||
chData.fwhmFitResultCoeffs.append(params(0)); // k
|
||
chData.fwhmFitResultCoeffs.append(params(1)); // c
|
||
return true;
|
||
}
|
||
|
||
|
||
bool EnergyScaleForm::saveChannelDataToJson(const QString &filePath)
|
||
{
|
||
if (filePath.isEmpty()) return false;
|
||
|
||
QJsonObject rootObj;
|
||
QString remark;
|
||
if(systemEnble)
|
||
remark = ui->plainTextEdit_description->property("systemData").toString();
|
||
else
|
||
remark = ui->plainTextEdit_description->toPlainText().trimmed();
|
||
rootObj["Remark"] = remark;
|
||
|
||
for (auto it = m_channelList.begin(); it != m_channelList.end(); ++it) {
|
||
QString channelName = it.key();
|
||
const ChannelData& chData = it.value();
|
||
|
||
QJsonObject channelObj;
|
||
channelObj["EnergyFitDegree"] = chData.energyFitDegree;
|
||
|
||
// 能量拟合系数
|
||
QJsonArray energyCoeffsArr;
|
||
for (double coeff : chData.energyFitResultCoeffs) {
|
||
energyCoeffsArr.append(coeff);
|
||
}
|
||
channelObj["EnergyFitResultCoeffs"] = energyCoeffsArr;
|
||
|
||
// 拟合数据
|
||
QJsonArray fitDataArr;
|
||
for (const FitDataRow& row : chData.fitData) {
|
||
QJsonArray rowArr;
|
||
rowArr.append(row.daoSite);
|
||
rowArr.append(row.energy);
|
||
rowArr.append(row.fittingEnergy);
|
||
rowArr.append(row.energyFittingDeviation);
|
||
rowArr.append(row.resolution);
|
||
rowArr.append(row.fitResolution);
|
||
rowArr.append(row.resolutionFittingDeviation);
|
||
fitDataArr.append(rowArr);
|
||
}
|
||
channelObj["FitData"] = fitDataArr;
|
||
|
||
QJsonArray fwhmCoeffsArr;
|
||
for (double coeff : chData.fwhmFitResultCoeffs) {
|
||
fwhmCoeffsArr.append(coeff);
|
||
}
|
||
channelObj["FwhmFitResultCoeffs"] = fwhmCoeffsArr;
|
||
|
||
rootObj[channelName] = channelObj;
|
||
}
|
||
|
||
QJsonDocument doc(rootObj);
|
||
QFile file(filePath);
|
||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||
QMessageBox::critical(this, "错误", QString("保存文件失败:%1").arg(file.errorString()));
|
||
return false;
|
||
}
|
||
|
||
file.write(doc.toJson(QJsonDocument::Indented));
|
||
file.close();
|
||
return true;
|
||
}
|
||
|
||
bool EnergyScaleForm::isDaoSiteDuplicated(const QString &channelName, double daoSite)
|
||
{
|
||
if (!m_channelList.contains(channelName)) return false;
|
||
const auto& fitData = m_channelList[channelName].fitData;
|
||
for (const auto& row : fitData) {
|
||
if (qAbs(row.daoSite - daoSite) < 1e-3) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
|
||
void EnergyScaleForm::onItemDoubleClicked(QListWidgetItem *item)
|
||
{
|
||
if (!item) return;
|
||
ui->plainTextEdit_description->clear();
|
||
QString filePath = item->data(Qt::UserRole).toString();
|
||
if (filePath.isEmpty()) return;
|
||
ui->lineEdit_name->setText(item->text());
|
||
m_currentFilePath = filePath;
|
||
QString errorMsg;
|
||
m_channelList = parseJsonToChannels(filePath, errorMsg);
|
||
on_comboBox_channel_currentTextChanged(QStringLiteral(u"通道1"));
|
||
}
|
||
|
||
void EnergyScaleForm::on_comboBox_channel_currentTextChanged(const QString &text)
|
||
{
|
||
if (text.isEmpty()) {
|
||
return;
|
||
}
|
||
if (!m_channelList.contains(text)) {
|
||
ChannelData emptyData;
|
||
emptyData.energyFitDegree = 1;
|
||
m_channelList.insert(text, emptyData);
|
||
}
|
||
showChannelData(text);
|
||
showCurve();
|
||
}
|
||
|
||
void EnergyScaleForm::on_comboBox_fit_type_currentTextChanged(const QString &text)
|
||
{
|
||
if(text == QStringLiteral(u"一次拟合")) {
|
||
ui->label_fit_type_text->setText(QStringLiteral(u"y = a + bx"));
|
||
} else if(text == QStringLiteral(u"二次拟合")) {
|
||
ui->label_fit_type_text->setText(QStringLiteral(u"y = a + bx + c*x^2"));
|
||
}
|
||
showCurve();
|
||
}
|
||
|
||
void EnergyScaleForm::on_pBtn_Add_clicked()
|
||
{
|
||
QString channelName = ui->comboBox_channel->currentText();
|
||
QDialog dialog(this);
|
||
dialog.setWindowTitle("添加能量刻度点");
|
||
dialog.setFixedSize(300, 180); // 调整高度,预留分辨率输入
|
||
dialog.setModal(true);
|
||
QVBoxLayout* mainLayout = new QVBoxLayout(&dialog);
|
||
mainLayout->setSpacing(15);
|
||
mainLayout->setContentsMargins(20, 20, 20, 20);
|
||
|
||
// 道址输入
|
||
QHBoxLayout* daoLayout = new QHBoxLayout();
|
||
QLabel* daoLabel = new QLabel("道址:");
|
||
QLineEdit* daoEdit = new QLineEdit();
|
||
daoEdit->setPlaceholderText("请输入道址值(数字)");
|
||
QDoubleValidator* daoValidator = new QDoubleValidator(0, 100000, 3, daoEdit);
|
||
daoValidator->setNotation(QDoubleValidator::StandardNotation);
|
||
daoEdit->setValidator(daoValidator);
|
||
daoLayout->addWidget(daoLabel);
|
||
daoLayout->addWidget(daoEdit);
|
||
|
||
// 能量输入
|
||
QHBoxLayout* energyLayout = new QHBoxLayout();
|
||
QLabel* energyLabel = new QLabel("能量:");
|
||
QLineEdit* energyEdit = new QLineEdit();
|
||
energyEdit->setPlaceholderText("请输入能量值(数字)");
|
||
QDoubleValidator* energyValidator = new QDoubleValidator(0, 10000, 3, energyEdit);
|
||
energyValidator->setNotation(QDoubleValidator::StandardNotation);
|
||
energyEdit->setValidator(energyValidator);
|
||
energyLayout->addWidget(energyLabel);
|
||
energyLayout->addWidget(energyEdit);
|
||
|
||
//分辨率输入
|
||
QHBoxLayout* resolutionLayout = new QHBoxLayout();
|
||
QLabel* resolutionLabel = new QLabel("分辨率:");
|
||
QLineEdit* resolutionEdit = new QLineEdit();
|
||
resolutionEdit->setPlaceholderText("请输入分辨率(数字)");
|
||
QDoubleValidator* resolutionValidator = new QDoubleValidator(0, 1000, 3, resolutionEdit);
|
||
resolutionValidator->setNotation(QDoubleValidator::StandardNotation);
|
||
resolutionEdit->setValidator(resolutionValidator);
|
||
resolutionLayout->addWidget(resolutionLabel);
|
||
resolutionLayout->addWidget(resolutionEdit);
|
||
|
||
// 按钮行
|
||
QHBoxLayout* btnLayout = new QHBoxLayout();
|
||
QPushButton* okBtn = new QPushButton("确定");
|
||
QPushButton* cancelBtn = new QPushButton("取消");
|
||
okBtn->setDefault(true);
|
||
btnLayout->addStretch();
|
||
btnLayout->addWidget(okBtn);
|
||
btnLayout->addWidget(cancelBtn);
|
||
|
||
mainLayout->addLayout(daoLayout);
|
||
mainLayout->addLayout(energyLayout);
|
||
mainLayout->addLayout(resolutionLayout);
|
||
mainLayout->addLayout(btnLayout);
|
||
|
||
connect(okBtn, &QPushButton::clicked, &dialog, &QDialog::accept);
|
||
connect(cancelBtn, &QPushButton::clicked, &dialog, &QDialog::reject);
|
||
daoEdit->setFocus();
|
||
|
||
if (dialog.exec() != QDialog::Accepted) {
|
||
return;
|
||
}
|
||
|
||
QString daoStr = daoEdit->text().trimmed();
|
||
QString energyStr = energyEdit->text().trimmed();
|
||
QString resolutionStr = resolutionEdit->text().trimmed();
|
||
if (daoStr.isEmpty() || energyStr.isEmpty()) {
|
||
QMessageBox::warning(this, "输入错误", "道址和能量不能为空");
|
||
return;
|
||
}
|
||
|
||
bool daoOk = false, energyOk = false, resolutionOk = false;
|
||
double daoSite = daoStr.toDouble(&daoOk);
|
||
double energy = energyStr.toDouble(&energyOk);
|
||
double resolution = resolutionStr.isEmpty() ? 0.0 : resolutionStr.toDouble(&resolutionOk);
|
||
if (!daoOk || !energyOk || (!resolutionStr.isEmpty() && !resolutionOk)) {
|
||
QMessageBox::warning(this, "输入错误", "请输入有效的数字");
|
||
return;
|
||
}
|
||
|
||
if (isDaoSiteDuplicated(channelName, daoSite)) {
|
||
QMessageBox::warning(this, "输入错误", "该道址已存在,无法重复添加");
|
||
return;
|
||
}
|
||
|
||
ChannelData& chData = m_channelList[channelName];
|
||
QTableWidget* table = ui->tablew_scale_data;
|
||
FitDataRow newRow;
|
||
newRow.daoSite = daoSite;
|
||
newRow.energy = energy;
|
||
newRow.resolution = resolution;
|
||
newRow.fittingEnergy = 0.0;
|
||
newRow.energyFittingDeviation = 0.0;
|
||
newRow.fitResolution = 0.0;
|
||
newRow.resolutionFittingDeviation = 0.0;
|
||
chData.fitData.append(newRow);
|
||
|
||
m_isLoadingTable = true;
|
||
int newRowIndex = table->rowCount();
|
||
table->insertRow(newRowIndex);
|
||
table->setItem(newRowIndex, 0, new QTableWidgetItem(QString::number(daoSite, 'f', 3)));
|
||
table->setItem(newRowIndex, 1, new QTableWidgetItem(QString::number(energy, 'f', 3)));
|
||
table->setItem(newRowIndex, 4, new QTableWidgetItem(QString::number(resolution, 'f', 3)));
|
||
for (int col = 2; col < 7; ++col) {
|
||
if (col != 4) {
|
||
table->setItem(newRowIndex, col, new QTableWidgetItem("0.000"));
|
||
}
|
||
}
|
||
for (int col = 0; col < 7; ++col) {
|
||
Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
|
||
if (col == 0 || col == 1 || col == 4) {
|
||
flags |= Qt::ItemIsEditable;
|
||
}
|
||
table->item(newRowIndex, col)->setFlags(flags);
|
||
}
|
||
m_isLoadingTable = false;
|
||
|
||
table->scrollToBottom();
|
||
table->selectRow(newRowIndex);
|
||
showCurve();
|
||
QMessageBox::information(this, "成功", "数据点添加成功");
|
||
}
|
||
|
||
|
||
void EnergyScaleForm::on_pBtn_Delete_clicked()
|
||
{
|
||
|
||
QTableWidget* table = ui->tablew_scale_data;
|
||
int currentRow = table->currentRow();
|
||
if (currentRow < 0 || currentRow >= table->rowCount()) {
|
||
QMessageBox::warning(this, "提示", "请选中要删除的行");
|
||
return;
|
||
}
|
||
|
||
if (QMessageBox::question(this, "确认", "是否删除选中的行?", QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) {
|
||
return;
|
||
}
|
||
|
||
table->removeRow(currentRow);
|
||
|
||
QString channelName = ui->comboBox_channel->currentText();
|
||
if (m_channelList.contains(channelName)) {
|
||
ChannelData& chData = m_channelList[channelName];
|
||
if (currentRow < chData.fitData.size()) {
|
||
chData.fitData.remove(currentRow);
|
||
}
|
||
// 删除后重新计算拟合值(如果有拟合系数)
|
||
calculateFitValues(chData);
|
||
// 刷新表格显示
|
||
showChannelData(channelName);
|
||
}
|
||
|
||
showCurve();
|
||
}
|
||
|
||
|
||
void EnergyScaleForm::on_pBtn_fitting_clicked()
|
||
{
|
||
QString channelName = ui->comboBox_channel->currentText();
|
||
if (!m_channelList.contains(channelName)) {
|
||
QMessageBox::warning(this, "拟合失败", "当前通道无数据");
|
||
return;
|
||
}
|
||
|
||
ChannelData& chData = m_channelList[channelName];
|
||
int rowCount = ui->tablew_scale_data->rowCount();
|
||
int fitDegree = ui->comboBox_fit_type->currentIndex() + 1;
|
||
int minEnergyPoints = (fitDegree == 1) ? 2 : 3;
|
||
|
||
if (rowCount < minEnergyPoints) {
|
||
QMessageBox::warning(this, "拟合失败",
|
||
QString("至少需要%1个数据点才能进行%2").arg(minEnergyPoints).arg(fitDegree == 1 ? "一次拟合" : "二次拟合"));
|
||
return;
|
||
}
|
||
|
||
std::vector<double> xRow,yRow;
|
||
for(int i = 0; i < rowCount;++i) {
|
||
QTableWidgetItem* daoItem = ui->tablew_scale_data->item(i,0);
|
||
QTableWidgetItem* energyItem = ui->tablew_scale_data->item(i,1);
|
||
if (!daoItem || !energyItem) continue;
|
||
bool daoOk = false, energyOk = false;
|
||
double dao = daoItem->text().toDouble(&daoOk);
|
||
double energy = energyItem->text().toDouble(&energyOk);
|
||
if (daoOk && energyOk) {
|
||
xRow.push_back(dao);
|
||
yRow.push_back(energy);
|
||
}
|
||
}
|
||
if (xRow.size() < minEnergyPoints || yRow.size() < minEnergyPoints) {
|
||
QMessageBox::warning(this, "拟合失败", "有效能量数据点不足");
|
||
return;
|
||
}
|
||
|
||
std::vector<double> energyCoeff = GaussPolyCoe::PolynomialFit(xRow, yRow, fitDegree);
|
||
if (energyCoeff.size() < fitDegree + 1) {
|
||
QMessageBox::warning(this, "拟合失败", "能量拟合计算出错");
|
||
return;
|
||
}
|
||
chData.energyFitDegree = fitDegree;
|
||
chData.energyFitResultCoeffs.clear();
|
||
for (double coeff : energyCoeff) {
|
||
chData.energyFitResultCoeffs.append(coeff);
|
||
}
|
||
|
||
fitFwhmModel(chData);
|
||
|
||
|
||
calculateFitValues(chData);
|
||
|
||
m_isLoadingTable = true;
|
||
showChannelData(channelName);
|
||
m_isLoadingTable = false;
|
||
showCurve();
|
||
|
||
QString energyMsg;
|
||
if (fitDegree == 1) {
|
||
energyMsg = QString("能量拟合成功:a = %1 , b = %2")
|
||
.arg(energyCoeff[0], 0, 'f', 6)
|
||
.arg(energyCoeff[1], 0, 'f', 6);
|
||
} else {
|
||
energyMsg = QString("能量拟合成功:a = %1 , b = %2 , c = %3")
|
||
.arg(energyCoeff[0], 0, 'f', 6)
|
||
.arg(energyCoeff[1], 0, 'f', 6)
|
||
.arg(energyCoeff[2], 0, 'f', 6);
|
||
}
|
||
}
|
||
|
||
void EnergyScaleForm::on_tablew_scale_data_cellChanged(int row, int column)
|
||
{
|
||
if (m_isLoadingTable) return;
|
||
|
||
QString channelName = ui->comboBox_channel->currentText();
|
||
if (!m_channelList.contains(channelName)) return;
|
||
if (row < 0 || row >= m_channelList[channelName].fitData.size()) return;
|
||
|
||
ChannelData& chData = m_channelList[channelName];
|
||
FitDataRow& currentRow = chData.fitData[row];
|
||
QTableWidgetItem* item = ui->tablew_scale_data->item(row, column);
|
||
if (!item) return;
|
||
|
||
bool ok = false;
|
||
double value = item->text().toDouble(&ok);
|
||
if (!ok) {
|
||
// 输入非数字时恢复原值
|
||
m_isLoadingTable = true;
|
||
if (column == 0) {
|
||
item->setText(QString::number(currentRow.daoSite, 'f', 3));
|
||
} else if (column == 1) {
|
||
item->setText(QString::number(currentRow.energy, 'f', 3));
|
||
} else if (column == 4) {
|
||
item->setText(QString::number(currentRow.resolution, 'f', 3));
|
||
}
|
||
m_isLoadingTable = false;
|
||
QMessageBox::warning(this, "输入错误", "请输入有效的数字");
|
||
return;
|
||
}
|
||
|
||
bool needRecalc = false;
|
||
if (column == 0) {
|
||
// 检查道址重复
|
||
if (isDaoSiteDuplicated(channelName, value) && qAbs(currentRow.daoSite - value) > 1e-3) {
|
||
m_isLoadingTable = true;
|
||
item->setText(QString::number(currentRow.daoSite, 'f', 3));
|
||
m_isLoadingTable = false;
|
||
QMessageBox::warning(this, "提示", "道址重复,修改失败");
|
||
return;
|
||
}
|
||
currentRow.daoSite = value;
|
||
needRecalc = true;
|
||
} else if (column == 1) {
|
||
currentRow.energy = value;
|
||
needRecalc = true;
|
||
} else if (column == 4) {
|
||
currentRow.resolution = value;
|
||
needRecalc = true;
|
||
}
|
||
|
||
if (needRecalc) {
|
||
// calculateFitValues(chData);
|
||
// m_isLoadingTable = true;
|
||
// showChannelData(channelName);
|
||
// m_isLoadingTable = false;
|
||
// showCurve();
|
||
on_pBtn_fitting_clicked();
|
||
}
|
||
|
||
}
|
||
|
||
void EnergyScaleForm::on_pBtn_SaveAs_clicked()
|
||
{
|
||
QString SaveAsName = ui->pBtn_SaveAs->text();
|
||
QString targetFilePath;
|
||
QString fileName;
|
||
QString remark;
|
||
if(SaveAsName.contains("保存到系统"))
|
||
{
|
||
systemEnble = true;
|
||
QDialog dialog(this);
|
||
dialog.setWindowTitle(QStringLiteral(u"保存到系统 - 能量刻度配置"));
|
||
dialog.setFixedSize(400, 250);
|
||
dialog.setModal(true);
|
||
|
||
QVBoxLayout* mainLayout = new QVBoxLayout(&dialog);
|
||
mainLayout->setSpacing(15);
|
||
mainLayout->setContentsMargins(20, 20, 20, 20);
|
||
|
||
QHBoxLayout* nameLayout = new QHBoxLayout();
|
||
QLabel* nameLabel = new QLabel(QStringLiteral(u"能量刻度名称:"));
|
||
QLineEdit* nameEdit = new QLineEdit();
|
||
nameEdit->setPlaceholderText(QStringLiteral(u"请输入刻度名称:"));
|
||
|
||
if (!ui->lineEdit_name->text().isEmpty()) {
|
||
QString baseName = ui->lineEdit_name->text();
|
||
baseName = baseName.contains("[") ? baseName.split("]").last().trimmed() : baseName;
|
||
nameEdit->setText(baseName);
|
||
}
|
||
nameLayout->addWidget(nameLabel);
|
||
nameLayout->addWidget(nameEdit);
|
||
|
||
// 备注输入框
|
||
QVBoxLayout* remarkLayout = new QVBoxLayout();
|
||
QLabel* remarkLabel = new QLabel(QStringLiteral(u"备注:"));
|
||
QTextEdit* remarkEdit = new QTextEdit();
|
||
remarkEdit->setPlaceholderText(QStringLiteral(u"请输入备注信息(可选)"));
|
||
remarkEdit->setPlainText(ui->plainTextEdit_description->toPlainText()); // 填充现有备注
|
||
remarkLayout->addWidget(remarkLabel);
|
||
remarkLayout->addWidget(remarkEdit);
|
||
|
||
// 按钮组
|
||
QHBoxLayout* btnLayout = new QHBoxLayout();
|
||
QPushButton* okBtn = new QPushButton(QStringLiteral(u"保存"));
|
||
QPushButton* cancelBtn = new QPushButton(QStringLiteral(u"取消"));
|
||
okBtn->setDefault(true);
|
||
btnLayout->addStretch();
|
||
btnLayout->addWidget(okBtn);
|
||
btnLayout->addWidget(cancelBtn);
|
||
|
||
// 组装布局
|
||
mainLayout->addLayout(nameLayout);
|
||
mainLayout->addLayout(remarkLayout);
|
||
mainLayout->addLayout(btnLayout);
|
||
|
||
connect(okBtn, &QPushButton::clicked, &dialog, &QDialog::accept);
|
||
connect(cancelBtn, &QPushButton::clicked, &dialog, &QDialog::reject);
|
||
|
||
if (dialog.exec() != QDialog::Accepted) {
|
||
return;
|
||
}
|
||
|
||
fileName = nameEdit->text().trimmed();
|
||
remark = remarkEdit->toPlainText().trimmed();
|
||
if (fileName.isEmpty()) {
|
||
QMessageBox::warning(this, QStringLiteral(u"输入错误"), QStringLiteral(u"能量刻度名称不能为空!"));
|
||
return;
|
||
}
|
||
QString defaultDir = QDir(qApp->applicationDirPath()).filePath("configure/EnergyScale");
|
||
|
||
QDir dir(defaultDir);
|
||
if (!dir.exists() && !dir.mkpath(".")) {
|
||
QMessageBox::critical(this, QStringLiteral(u"错误"), QStringLiteral(u"无法创建目录:%1").arg(defaultDir));
|
||
return;
|
||
}
|
||
targetFilePath = dir.filePath(fileName + ".json"); // 强制.json后缀
|
||
|
||
if (QFile::exists(targetFilePath)) {
|
||
QMessageBox::StandardButton ret = QMessageBox::question(
|
||
this,
|
||
QStringLiteral(u"文件已存在"),
|
||
QStringLiteral(u"名称为“%1”的能量刻度文件已存在,是否覆盖?").arg(fileName),
|
||
QMessageBox::Yes | QMessageBox::No,
|
||
QMessageBox::No
|
||
);
|
||
if (ret != QMessageBox::Yes) {
|
||
return;
|
||
}
|
||
}
|
||
ui->plainTextEdit_description->setProperty("systemData",remark);
|
||
}else{
|
||
systemEnble = false;
|
||
// 选择保存路径
|
||
QString defaultDir = QDir(qApp->applicationDirPath()).filePath("configure/EnergyScale");
|
||
targetFilePath = QFileDialog::getSaveFileName(this,
|
||
"另存为能量刻度文件",
|
||
defaultDir,
|
||
"JSON文件 (*.json);;所有文件 (*.*)");
|
||
|
||
if (targetFilePath.isEmpty()) {
|
||
return;
|
||
}
|
||
|
||
// 确保后缀是.json
|
||
if (!targetFilePath.endsWith(".json", Qt::CaseInsensitive)) {
|
||
targetFilePath += ".json";
|
||
}
|
||
}
|
||
// 保存文件
|
||
if (saveChannelDataToJson(targetFilePath)) {
|
||
// m_currentFilePath = targetFilePath; // 更新当前文件路径
|
||
// ui->lineEdit_name->setText(QFileInfo(targetFilePath).baseName());
|
||
loadAllFilesInTheFolder();
|
||
}
|
||
}
|
||
|
||
void EnergyScaleForm::on_pBtn_Save_clicked()
|
||
{
|
||
systemEnble = false;
|
||
if (saveChannelDataToJson(m_currentFilePath)) {
|
||
QMessageBox::information(this, "成功", "数据保存成功");
|
||
} else {
|
||
QMessageBox::critical(this, "失败", "数据保存失败");
|
||
}
|
||
}
|
||
|
||
|
||
void EnergyScaleForm::on_pBtn_Add_File_clicked()
|
||
{
|
||
bool isOk = false;
|
||
QString fileName = QInputDialog::getText(this,
|
||
QStringLiteral(u"新建能量刻度文件"),
|
||
QStringLiteral(u"请输入文件名(无需后缀):"),
|
||
QLineEdit::Normal,
|
||
QStringLiteral(u"新刻度文件"),
|
||
&isOk);
|
||
if (!isOk || fileName.trimmed().isEmpty()) {
|
||
return; // 用户取消或输入为空
|
||
}
|
||
fileName = fileName.trimmed();
|
||
const QString energyScaleDir = QDir(qApp->applicationDirPath()).filePath("configure/EnergyScale");
|
||
QDir dir(energyScaleDir);
|
||
if (!dir.exists() && !dir.mkpath(".")) {
|
||
QMessageBox::critical(this, QStringLiteral(u"错误"),
|
||
QStringLiteral(u"无法创建目录:%1").arg(energyScaleDir));
|
||
return;
|
||
}
|
||
|
||
QString filePath = dir.filePath(fileName + ".json");
|
||
if (QFile::exists(filePath)) {
|
||
QMessageBox::warning(this, QStringLiteral(u"提示"),
|
||
QStringLiteral(u"文件%1已存在,请更换文件名").arg(fileName));
|
||
return;
|
||
}
|
||
|
||
QJsonObject rootObj;
|
||
for (int i = 1; i <= 32; ++i) {
|
||
QString channelName = QStringLiteral(u"通道%1").arg(i);
|
||
QJsonObject channelObj;
|
||
channelObj["EnergyFitDegree"] = 1; // 默认一次拟合
|
||
channelObj["EnergyFitResultCoeffs"] = QJsonArray(); // 空系数
|
||
channelObj["FitData"] = QJsonArray(); // 空拟合数据
|
||
channelObj["FwhmFitResultCoeffs"] = QJsonArray(); // 空分辨率系数
|
||
rootObj[channelName] = channelObj;
|
||
}
|
||
|
||
QJsonDocument doc(rootObj);
|
||
QFile file(filePath);
|
||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||
QMessageBox::critical(this, QStringLiteral(u"错误"),
|
||
QStringLiteral(u"无法创建文件:%1\n%2").arg(filePath).arg(file.errorString()));
|
||
return;
|
||
}
|
||
file.write(doc.toJson(QJsonDocument::Indented));
|
||
file.close();
|
||
|
||
loadAllFilesInTheFolder();
|
||
for (int i = 0; i < ui->listWidget->count(); ++i) {
|
||
QListWidgetItem* item = ui->listWidget->item(i);
|
||
if (item->text() == fileName) {
|
||
ui->listWidget->setCurrentItem(item);
|
||
break;
|
||
}
|
||
}
|
||
|
||
QMessageBox::information(this, QStringLiteral(u"成功"),
|
||
QStringLiteral(u"文件%1创建成功").arg(fileName + ".json"));
|
||
}
|
||
|
||
|
||
void EnergyScaleForm::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->tablew_scale_data->setRowCount(0);
|
||
clearPlot();
|
||
_plot->replot();
|
||
ui->label_fit_result->clear();
|
||
ui->label_fit_type_text->clear();
|
||
}
|
||
QMessageBox::information(this, QStringLiteral(u"成功"),
|
||
QStringLiteral(u"删除成功"));
|
||
} else {
|
||
QMessageBox::critical(this, QStringLiteral(u"错误"),
|
||
QStringLiteral(u"删除失败:%1").arg(filePath));
|
||
}
|
||
}
|
||
|