添加测量设备参数管理交互实现

This commit is contained in:
徐海 2026-05-07 10:23:23 +08:00
parent 79b68ba1d6
commit 664b115aaa
30 changed files with 1125 additions and 2541 deletions

Binary file not shown.

View File

@ -6,7 +6,7 @@ LIBS += -L$$PWD/armadillo/lib -llibblas
LIBS += -L$$PWD/armadillo/lib -lliblapack
SOURCES += \
$$PWD/CoincidenceSpectrum.cpp \
$$PWD/CoincidenceSpectrumProcess.cpp \
$$PWD/EnergyEfficiencyFit.cpp \
$$PWD/Poly2FindPeaks.cpp \
$$PWD/FindPeaksBySvd.cpp \

View File

@ -1,463 +0,0 @@
#include "DeviceConfigView.h"
#include "DeviceParameterProxy.h"
#include <QTableView>
#include <QStandardItemModel>
#include <QHeaderView>
#include <QPushButton>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QMessageBox>
#include <QDialog>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QListWidget>
#include <QDialogButtonBox>
#include <QLabel>
#include <QScrollArea>
#include <QCheckBox>
#include <QFileDialog>
#include <QStyleOptionButton>
#include <GlobalDefine.h>
#include <QObject>
#include <QDebug>
class DeviceConfigViewModel: public QStandardItemModel
{
public:
DeviceConfigViewModel(QObject *parent = nullptr) : QStandardItemModel(parent){}
virtual Qt::ItemFlags flags(const QModelIndex &index) const {
Qt::ItemFlags f = QStandardItemModel::flags(index);
if ( index.column() == 0 ) {
f = f & Qt::ItemIsUserCheckable;
}
return f;
}
};
DeviceConfigView::DeviceConfigView(QWidget *parent)
: MeasureAnalysisView(parent)
, m_tableView(nullptr)
, m_model(nullptr)
{
initTableView();
}
DeviceConfigView::~DeviceConfigView()
{
}
void DeviceConfigView::initTableView()
{
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
m_tableView = new QTableView(this);
layout->addWidget(m_tableView);
// 设置表头
QStringList headList;
headList << tr("数据传输模式") << tr("硬件增益") << tr("硬件增益选择索引")
<< tr("软件增益") << tr("时间常数") << tr("成形时间") << tr("快通道触发阈值")
<< tr("多道分辨率") << tr("控制功能") << tr("幅度提前延迟") << tr("积分长度")
<< tr("dcfd缩放倍数") << tr("dcfd延迟") << tr("直流偏移") << tr("最大能量范围")
<< tr("Am 峰面积寻峰法的面积比例") << tr("K40与 Am241的峰位校正系数") << tr("高压关断阈值")
<< tr("获取能谱周期") << tr("总测量时间") << tr("总测量次数") << tr("滤波参数")
<< tr("上升时间") << tr("平顶时间") << tr("ICR 校正使能") << tr("CRZA 值")
<< tr("ZA 使能值") << tr("操作");
m_model = new DeviceConfigViewModel(this);
m_model->setColumnCount(headList.size());
m_model->setHorizontalHeaderLabels(headList);
m_model->setRowCount(32);
for (int i = 0; i < 32; ++i) {
QString rowName = tr("通道%1").arg(i + 1);
m_model->setHeaderData(i, Qt::Vertical, rowName, Qt::DisplayRole);
}
// 操作列最后一列不可编辑
int actionCol = headList.size() - 1;
for (int row = 0; row < 32; ++row) {
QStandardItem *item = new QStandardItem(QString());
item->setFlags(item->flags() & ~Qt::ItemIsEditable);
m_model->setItem(row, actionCol, item);
}
m_tableView->setModel(m_model);
m_tableView->verticalHeader()->setSectionResizeMode(QHeaderView::Interactive);
m_tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
m_tableView->setEditTriggers(QAbstractItemView::DoubleClicked);
// 设置代理
DeviceParameterProxy *proxy = new DeviceParameterProxy(this);
m_tableView->setItemDelegate(proxy);
setupActionColumnButtons();
}
void DeviceConfigView::setupActionColumnButtons()
{
int actionCol = m_model->columnCount() - 1;
for (int row = 0; row < m_model->rowCount(); ++row) {
QModelIndex idx_0 = m_model->index(row, 0);
QModelIndex idx = m_model->index(row, actionCol);
QPushButton *btn = new QPushButton(tr("应用"), m_tableView);
btn->setProperty("row", row);
connect(btn, &QPushButton::clicked, this, &DeviceConfigView::onActionButtonClicked);
m_tableView->setIndexWidget(idx, btn);
}
}
void DeviceConfigView::onActionButtonClicked()
{
QPushButton *btn = qobject_cast<QPushButton*>(sender());
if (!btn) return;
int srcRow = btn->property("row").toInt();
int srcChannel = srcRow + 1;
QList<int> targetChannels = selectTargetChannels(srcChannel);
if (targetChannels.isEmpty()) return;
int paramColCount = m_model->columnCount() - 1;
m_model->blockSignals(true);
for (int ch : targetChannels) {
int dstRow = ch - 1;
if (dstRow == srcRow) continue;
for (int col = 0; col < paramColCount; ++col) {
QVariant srcData = m_model->data(m_model->index(srcRow, col));
m_model->setData(m_model->index(dstRow, col), srcData);
}
}
m_model->blockSignals(false);
emit m_model->dataChanged(m_model->index(0, 0), m_model->index(m_model->rowCount() - 1, paramColCount - 1));
QMessageBox::information(this, tr("提示"),
tr("已成功将通道%1的参数应用到 %2 个通道").arg(srcChannel).arg(targetChannels.size()));
}
QList<int> DeviceConfigView::selectTargetChannels(int currentChannel) const
{
QDialog dlg(const_cast<DeviceConfigView*>(this));
dlg.setWindowTitle(tr("选择目标通道"));
dlg.resize(300, 400);
QVBoxLayout *layout = new QVBoxLayout(&dlg);
QLabel *label = new QLabel(tr("请选择要应用参数的目标通道(可多选):"));
layout->addWidget(label);
QListWidget *listWidget = new QListWidget(&dlg);
for (int i = 1; i <= 32; ++i) {
QString itemText = tr("通道 %1").arg(i);
if (i == currentChannel) itemText += tr(" (源通道)");
QListWidgetItem *item = new QListWidgetItem(itemText, listWidget);
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
item->setCheckState(Qt::Unchecked);
item->setData(Qt::UserRole, i);
if (i == currentChannel) {
item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
}
}
layout->addWidget(listWidget);
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dlg);
layout->addWidget(buttonBox);
connect(buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept);
connect(buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject);
QList<int> selected;
if (dlg.exec() == QDialog::Accepted) {
for (int i = 0; i < listWidget->count(); ++i) {
QListWidgetItem *item = listWidget->item(i);
if (item->checkState() == Qt::Checked) {
int ch = item->data(Qt::UserRole).toInt();
if (ch != currentChannel) selected.append(ch);
}
}
}
return selected;
}
bool DeviceConfigView::loadJson(const QString &filePath)
{
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qWarning() << "无法打开文件:" << file.errorString();
return false;
}
QByteArray jsonData = file.readAll();
file.close();
return parseJsonImpl(jsonData);
}
bool DeviceConfigView::parseJsonImpl(const QByteArray &data)
{
QJsonParseError parseError;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &parseError);
if (parseError.error != QJsonParseError::NoError) {
qWarning() << "JSON 解析错误:" << parseError.errorString();
return false;
}
if (!jsonDoc.isObject()) {
qWarning() << "JSON 文档不是对象";
return false;
}
QJsonObject rootObj = jsonDoc.object();
QJsonArray channelsArray = rootObj["channels"].toArray();
m_model->blockSignals(true);
// 清空现有数据
for (int row = 0; row < m_model->rowCount(); ++row) {
for (int col = 0; col < m_model->columnCount(); ++col) {
m_model->setData(m_model->index(row, col), QVariant());
}
}
int count = qMin(channelsArray.size(), m_model->rowCount());
for (int i = 0; i < count; ++i) {
QJsonValue channelValue = channelsArray[i];
if (!channelValue.isObject()) continue;
QJsonObject channelObj = channelValue.toObject();
for (int col = 0; col < m_model->columnCount(); ++col) {
QString header = m_model->headerData(col, Qt::Horizontal).toString();
QString jsonKey = m_columnToJsonKey.value(header);
if (jsonKey.isEmpty()) continue;
QJsonValue value = channelObj[jsonKey];
if (value.isUndefined()) continue;
if (value.isString())
m_model->setData(m_model->index(i, col), value.toString());
else if (value.isDouble())
m_model->setData(m_model->index(i, col), value.toDouble());
else if (value.isBool())
m_model->setData(m_model->index(i, col), value.toBool());
}
}
emit m_model->dataChanged(m_model->index(0, 0), m_model->index(m_model->rowCount() - 1, m_model->columnCount() - 1));
emit dataChanged();
m_tableView->viewport()->update();
m_tableView->horizontalHeader()->update();
m_tableView->verticalHeader()->update();
return true;
}
bool DeviceConfigView::saveJson(const QString &filePath)
{
QJsonObject rootObj;
rootObj["command"] = "SET";
QJsonArray channelsArray;
for (int row = 0; row < m_model->rowCount(); ++row) {
QJsonObject channelObj;
for (int col = 0; col < m_model->columnCount(); ++col) {
QString header = m_model->headerData(col, Qt::Horizontal).toString();
QString jsonKey = m_columnToJsonKey.value(header);
if (jsonKey.isEmpty()) continue;
QVariant value = m_model->index(row, col).data(Qt::EditRole);
if (!value.isValid() || value.isNull()) continue;
channelObj[jsonKey] = QJsonValue::fromVariant(value);
}
channelsArray.append(channelObj);
}
rootObj["channels"] = channelsArray;
QFile file(filePath);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qWarning() << "无法创建文件:" << file.errorString();
return false;
}
QJsonDocument doc(rootObj);
file.write(doc.toJson());
file.close();
return true;
}
QStandardItemModel* DeviceConfigView::getModel() const
{
return m_model;
}
void DeviceConfigView::showColumnControlDialog()
{
int colCount = m_model->columnCount();
if (colCount == 0) return;
QDialog dlg(this);
dlg.setWindowTitle(tr("列显示控制"));
dlg.resize(800, 400);
dlg.setWindowModality(Qt::WindowModal);
QVBoxLayout *mainLayout = new QVBoxLayout(&dlg);
// 工具栏
QHBoxLayout *row1Layout = new QHBoxLayout();
QPushButton *btnSelectAll = new QPushButton(tr("全选"));
QPushButton *btnInvert = new QPushButton(tr("反选"));
QPushButton *btnSave = new QPushButton(tr("保存配置"));
QPushButton *btnLoad = new QPushButton(tr("加载配置"));
row1Layout->addWidget(btnSelectAll);
row1Layout->addWidget(btnInvert);
row1Layout->addWidget(btnSave);
row1Layout->addWidget(btnLoad);
row1Layout->addStretch();
mainLayout->addLayout(row1Layout);
QScrollArea *scrollArea = new QScrollArea();
scrollArea->setWidgetResizable(true);
QWidget *scrollWidget = new QWidget();
QGridLayout *gridLayout = new QGridLayout(scrollWidget);
scrollArea->setWidget(scrollWidget);
mainLayout->addWidget(scrollArea);
int gridCols = std::sqrt(colCount);
if (gridCols < 1) gridCols = 1;
QMap<int, QCheckBox*> colCheckBoxMap;
for (int col = 0; col < colCount; ++col) {
QString header = m_model->headerData(col, Qt::Horizontal).toString();
QCheckBox *cb = new QCheckBox(header);
cb->setChecked(!m_tableView->isColumnHidden(col));
connect(cb, &QCheckBox::toggled, this, [this, col](bool checked) {
m_tableView->setColumnHidden(col, !checked);
});
int row = col / gridCols;
int colInGrid = col % gridCols;
gridLayout->addWidget(cb, row, colInGrid);
colCheckBoxMap[col] = cb;
}
connect(btnSelectAll, &QPushButton::clicked, this, [colCheckBoxMap, this]() {
// 先断开所有复选框的信号
for (QCheckBox *cb : colCheckBoxMap) {
cb->blockSignals(true);
cb->setChecked(true);
cb->blockSignals(false);
}
// 一次性更新所有列的隐藏状态
for (int col : colCheckBoxMap.keys()) {
m_tableView->setColumnHidden(col, !colCheckBoxMap[col]->isChecked());
}
});
connect(btnInvert, &QPushButton::clicked, this, [colCheckBoxMap, this]() {
for (QCheckBox *cb : colCheckBoxMap) {
cb->blockSignals(true);
cb->setChecked(!cb->isChecked());
cb->blockSignals(false);
}
for (int col : colCheckBoxMap.keys()) {
m_tableView->setColumnHidden(col, !colCheckBoxMap[col]->isChecked());
}
});
connect(btnSave, &QPushButton::clicked, this, [this, &dlg, colCheckBoxMap]() {
QString saveDir = QDir::currentPath() + "/columnConfigs";
QDir().mkpath(saveDir);
QString fileName = QFileDialog::getSaveFileName(&dlg, tr("保存列配置"),
saveDir + "/untitled.json",
"JSON Files (*.json)");
if (fileName.isEmpty()) return;
QJsonObject root;
for (int col = 0; col < m_model->columnCount(); ++col) {
QString header = m_model->headerData(col, Qt::Horizontal).toString();
bool checked = colCheckBoxMap[col]->isChecked();
root[header] = checked;
}
QJsonDocument doc(root);
QFile file(fileName);
if (file.open(QIODevice::WriteOnly)) {
file.write(doc.toJson());
file.close();
QMessageBox::information(&dlg, tr("成功"), tr("列配置已保存"));
} else {
QMessageBox::warning(&dlg, tr("错误"), tr("无法保存文件:%1").arg(file.errorString()));
}
});
connect(btnLoad, &QPushButton::clicked, this, [this, &dlg, colCheckBoxMap]() {
QString loadDir = QDir::currentPath() + "/columnConfigs";
QString fileName = QFileDialog::getOpenFileName(&dlg, tr("加载列配置"),
loadDir, "JSON Files (*.json)");
if (fileName.isEmpty()) return;
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
QMessageBox::warning(&dlg, tr("错误"), tr("无法打开文件:%1").arg(file.errorString()));
return;
}
QByteArray data = file.readAll();
file.close();
QJsonParseError err;
QJsonDocument doc = QJsonDocument::fromJson(data, &err);
if (err.error != QJsonParseError::NoError || !doc.isObject()) {
QMessageBox::warning(&dlg, tr("错误"), tr("JSON解析失败"));
return;
}
QJsonObject root = doc.object();
for (int col = 0; col < m_model->columnCount(); ++col) {
QString header = m_model->headerData(col, Qt::Horizontal).toString();
if (root.contains(header)) {
colCheckBoxMap[col]->blockSignals(true);
colCheckBoxMap[col]->setChecked(root[header].toBool(false));
colCheckBoxMap[col]->blockSignals(false);
}
}
// 一次性更新列隐藏
for (int col : colCheckBoxMap.keys()) {
m_tableView->setColumnHidden(col, !colCheckBoxMap[col]->isChecked());
}
});
dlg.exec();
}
void DeviceConfigView::reset()
{
m_model->blockSignals(true);
for (int row = 0; row < m_model->rowCount(); ++row) {
for (int col = 0; col < m_model->columnCount(); ++col) {
m_model->setData(m_model->index(row, col), QVariant());
}
}
m_model->blockSignals(false);
emit m_model->dataChanged(m_model->index(0, 0), m_model->index(m_model->rowCount() - 1, m_model->columnCount() - 1));
}
void DeviceConfigView::setColumnMapping(const QHash<QString, QString> &mapping)
{
m_columnToJsonKey = mapping;
// 构建反向映射(可选)
m_jsonKeyToColumn.clear();
for (auto it = m_columnToJsonKey.constBegin(); it != m_columnToJsonKey.constEnd(); ++it) {
m_jsonKeyToColumn[it.value()] = m_model->headerData(0, Qt::Horizontal, Qt::DisplayRole).toString().indexOf(it.key());
}
}
void DeviceConfigView::InitViewWorkspace(const QString &project_name)
{
}
void DeviceConfigView::SetAnalyzeDataFilename(const QMap<QString, QVariant> &data_files_set)
{
if (data_files_set.isEmpty()) {
LOG_WARN("文件集合为空");
return;
}
QString filePath = data_files_set.first().toString();
LOG_INFO("读取文件: " + filePath);
}

View File

@ -1,62 +0,0 @@
#ifndef DEVICECONFIGVIEW_H
#define DEVICECONFIGVIEW_H
#include <QWidget>
#include <QHash>
#include "MeasureAnalysisView.h"
class QTableView;
class QStandardItemModel;
class QPushButton;
class DeviceConfigView : public MeasureAnalysisView
{
Q_OBJECT
public:
explicit DeviceConfigView(QWidget *parent = nullptr);
~DeviceConfigView();
bool loadJson(const QString &filePath);
bool saveJson(const QString &filePath);
QStandardItemModel* getModel() const;
void showColumnControlDialog();
void reset();
void setColumnMapping(const QHash<QString, QString> &mapping);
virtual void InitViewWorkspace(const QString& project_name) override final;
virtual void SetAnalyzeDataFilename(const QMap<QString, QVariant>& data_files_set);
QList<int> getCheckedRows() const;
signals:
void dataChanged();
private slots:
void onActionButtonClicked();
private:
void initTableView();
void setupActionColumnButtons();
bool parseJsonImpl(const QByteArray &data);
QList<int> selectTargetChannels(int currentChannel) const;
QTableView *m_tableView;
QStandardItemModel *m_model;
QHash<QString, QString> m_columnToJsonKey; // 列头 -> JSON键名
QHash<QString, int> m_jsonKeyToColumn; // 反向映射,用于快速查找列索引
};
#endif // DEVICECONFIGVIEW_H

View File

@ -1,333 +0,0 @@
#include "DeviceParameterConfig.h"
#include "DeviceParameterConfigList.h"
#include "DeviceConfigView.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QTextEdit>
#include <QCheckBox>
#include <QPushButton>
#include <QFile>
#include <QMessageBox>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QDir>
#include <QDebug>
DeviceParameterConfig::DeviceParameterConfig(QWidget *parent)
: QWidget(parent)
, m_configList(nullptr)
, m_configView(nullptr)
, m_lineEditFileName(nullptr)
, m_textEditRemark(nullptr)
, m_checkBoxSaveToDevice(nullptr)
, m_btnSave(nullptr)
, m_btnSetColumn(nullptr)
{
setupUi();
initColumnMapping(); // 设置默认映射
m_configView->setColumnMapping(m_columnToJsonKey);
m_configList->loadConfigsFromFolder(); // 加载默认目录下的配置文件
}
DeviceParameterConfig::~DeviceParameterConfig()
{
}
void DeviceParameterConfig::setupUi()
{
// 主布局:左右分栏
QHBoxLayout *mainLayout = new QHBoxLayout(this);
mainLayout->setContentsMargins(0, 0, 0, 0);
mainLayout->setSpacing(10);
// 左侧:配置列表
m_configList = new DeviceParameterConfigList(this);
mainLayout->addWidget(m_configList, 1);
// 右侧:垂直布局
QVBoxLayout *rightLayout = new QVBoxLayout();
mainLayout->addLayout(rightLayout, 9);
// 右侧上部:文件名、保存按钮、备注说明
QHBoxLayout *topLayout = new QHBoxLayout();
QLabel *labelName = new QLabel(QStringLiteral(u"配置命名:"), this);
m_lineEditFileName = new QLineEdit(this);
m_btnSave = new QPushButton(QStringLiteral(u"保存到测量分析"), this);
m_checkBoxSaveToDevice = new QCheckBox(QStringLiteral(u"保存到设备参数配置管理"), this);
topLayout->addWidget(labelName);
topLayout->addWidget(m_lineEditFileName, 1);
topLayout->addWidget(m_btnSave);
topLayout->addWidget(m_checkBoxSaveToDevice);
rightLayout->addLayout(topLayout);
QHBoxLayout *remarkLayout = new QHBoxLayout();
QLabel *labelRemark = new QLabel(QStringLiteral(u"备注说明:"), this);
m_textEditRemark = new QTextEdit(this);
m_textEditRemark->setMaximumHeight(80);
remarkLayout->addWidget(labelRemark);
remarkLayout->addWidget(m_textEditRemark, 1);
rightLayout->addLayout(remarkLayout);
// 右侧中部:设置列按钮
QHBoxLayout *buttonLayout = new QHBoxLayout();
m_btnSetColumn = new QPushButton(QStringLiteral(u"设置列"), this);
buttonLayout->addWidget(m_btnSetColumn);
buttonLayout->addStretch();
rightLayout->addLayout(buttonLayout);
// 右侧下部:参数表格视图
m_configView = new DeviceConfigView(this);
rightLayout->addWidget(m_configView, 1);
// 连接信号槽
connect(m_configList, &DeviceParameterConfigList::configSelected,
this, &DeviceParameterConfig::onConfigSelected);
connect(m_configList, &DeviceParameterConfigList::configDeleted,
this, &DeviceParameterConfig::onConfigDeleted);
connect(m_btnSave, &QPushButton::clicked,
this, &DeviceParameterConfig::onSaveButtonClicked);
connect(m_btnSetColumn, &QPushButton::clicked,
this, &DeviceParameterConfig::onSetColumnButtonClicked);
connect(m_configList, &DeviceParameterConfigList::createNewConfigRequested,
this, &DeviceParameterConfig::onCreateNewConfigRequested);
connect(m_configView, &DeviceConfigView::dataChanged,
this, [this]() {
// 数据改变时,在文件名后添加星号表示未保存
if (!m_lineEditFileName->text().isEmpty() && !m_lineEditFileName->text().endsWith(" *")) {
m_lineEditFileName->setText(m_lineEditFileName->text() + " *");
}
});
}
void DeviceParameterConfig::initColumnMapping()
{
// 与原 EquipmentParameterSettingManagement 完全相同的映射
m_columnToJsonKey.clear();
m_columnToJsonKey[QStringLiteral(u"数据传输模式")] = "eTransferModel";
m_columnToJsonKey[QStringLiteral(u"硬件增益")] = "iDeviceGain";
m_columnToJsonKey[QStringLiteral(u"硬件增益选择索引")] = "iDeviceGainSelectIndex";
m_columnToJsonKey[QStringLiteral(u"软件增益")] = "iSoftGain";
m_columnToJsonKey[QStringLiteral(u"时间常数")] = "dConstTime";
m_columnToJsonKey[QStringLiteral(u"成形时间")] = "iFormTime";
m_columnToJsonKey[QStringLiteral(u"快通道触发阈值")] = "iFastChannelTrigerValue";
m_columnToJsonKey[QStringLiteral(u"多道分辨率")] = "iChannelNum";
m_columnToJsonKey[QStringLiteral(u"控制功能")] = "";
m_columnToJsonKey[QStringLiteral(u"幅度提前延迟")] = "";
m_columnToJsonKey[QStringLiteral(u"积分长度")] = "";
m_columnToJsonKey[QStringLiteral(u"dcfd缩放倍数")] = "";
m_columnToJsonKey[QStringLiteral(u"dcfd延迟")] = "";
m_columnToJsonKey[QStringLiteral(u"直流偏移")] = "iCurrentOffset";
m_columnToJsonKey[QStringLiteral(u"最大能量范围")] = "iMaxEnergy";
m_columnToJsonKey[QStringLiteral(u"Am 峰面积寻峰法的面积比例")] = "iAMPeakDiv";
m_columnToJsonKey[QStringLiteral(u"K40与 Am241的峰位校正系数")] = "iHVDelt";
m_columnToJsonKey[QStringLiteral(u"高压关断阈值")] = "iHVDelt";
m_columnToJsonKey[QStringLiteral(u"获取能谱周期")] = "iGetSpecturmPeirod";
m_columnToJsonKey[QStringLiteral(u"总测量时间")] = "iTotalMeasureTime";
m_columnToJsonKey[QStringLiteral(u"总测量次数")] = "iTotalMeasureCount";
m_columnToJsonKey[QStringLiteral(u"滤波参数")] = "iTrapeTopShitBit";
m_columnToJsonKey[QStringLiteral(u"上升时间")] = "iRiseTime";
m_columnToJsonKey[QStringLiteral(u"平顶时间")] = "iTopTime";
m_columnToJsonKey[QStringLiteral(u"ICR 校正使能")] = "bICRCorrect";
m_columnToJsonKey[QStringLiteral(u"CRZA 值")] = "iCRZAValue";
m_columnToJsonKey[QStringLiteral(u"ZA 使能值")] = "iZAEnable";
}
void DeviceParameterConfig::setColumnMapping(const QHash<QString, QString> &mapping)
{
m_columnToJsonKey = mapping;
m_configView->setColumnMapping(mapping);
}
bool DeviceParameterConfig::loadConfig(const QString &filePath)
{
if (!m_configView->loadJson(filePath))
return false;
m_currentFilePath = filePath;
QFileInfo info(filePath);
m_lineEditFileName->setText(info.fileName());
// 读取 JSON 中的备注字段
QFile file(filePath);
if (file.open(QIODevice::ReadOnly)) {
QByteArray data = file.readAll();
file.close();
QJsonDocument doc = QJsonDocument::fromJson(data);
if (doc.isObject()) {
QJsonObject obj = doc.object();
if (obj.contains("remark")) {
m_textEditRemark->setPlainText(obj["remark"].toString());
} else {
m_textEditRemark->clear();
}
}
}
emit configLoaded(filePath); // 此信号未在头文件中声明,可添加;若不需要可移除
return true;
}
bool DeviceParameterConfig::saveCurrentConfig()
{
if (m_currentFilePath.isEmpty()) {
QMessageBox::warning(this, QStringLiteral(u"错误"), QStringLiteral(u"没有选中的配置文件"));
return false;
}
// 保存表格数据
if (!m_configView->saveJson(m_currentFilePath))
return false;
// 保存备注到 JSON
QFile file(m_currentFilePath);
if (!file.open(QIODevice::ReadOnly)) {
qWarning() << "无法打开文件读取备注:" << file.errorString();
return false;
}
QByteArray data = file.readAll();
file.close();
QJsonDocument doc = QJsonDocument::fromJson(data);
if (!doc.isObject()) {
qWarning() << "JSON 不是对象";
return false;
}
QJsonObject root = doc.object();
root["remark"] = m_textEditRemark->toPlainText();
if (!file.open(QIODevice::WriteOnly)) {
qWarning() << "无法写入文件:" << file.errorString();
return false;
}
file.write(QJsonDocument(root).toJson());
file.close();
// 移除文件名后的星号
QString fileName = m_lineEditFileName->text();
if (fileName.endsWith(" *"))
fileName.chop(2);
m_lineEditFileName->setText(fileName);
return true;
}
QString DeviceParameterConfig::getCurrentFileName() const
{
return QFileInfo(m_currentFilePath).fileName();
}
QString DeviceParameterConfig::getRemark() const
{
return m_textEditRemark->toPlainText();
}
void DeviceParameterConfig::setRemark(const QString &remark)
{
m_textEditRemark->setPlainText(remark);
}
void DeviceParameterConfig::onConfigSelected(const QString &filePath)
{
loadConfig(filePath);
}
void DeviceParameterConfig::onConfigDeleted(const QString &fileName)
{
if (m_lineEditFileName->text() == fileName) {
m_lineEditFileName->clear();
m_textEditRemark->clear();
m_configView->reset();
m_currentFilePath.clear();
}
}
void DeviceParameterConfig::onCreateNewConfigRequested(const QString &fileName)
{
QString filePath = QDir::currentPath() + "/parameterConfig/" + fileName;
if (createDefaultConfigFile(filePath)) {
// 刷新列表
m_configList->refresh();
// 选中新建的文件
m_configList->setCurrentFile(fileName);
// 自动加载该配置(可选)
loadConfig(filePath);
} else {
QMessageBox::warning(this, QStringLiteral(u"错误"), QStringLiteral(u"无法创建配置文件:%1").arg(filePath));
}
}
void DeviceParameterConfig::onSaveButtonClicked()
{
if (!saveCurrentConfig()) {
QMessageBox::warning(this, QStringLiteral(u"错误"), QStringLiteral(u"保存配置文件失败"));
return;
}
// 如果勾选了“保存到设备参数配置管理”,刷新左侧列表
if (m_checkBoxSaveToDevice->isChecked()) {
m_configList->refresh();
}
// 发出信号,供外部处理(例如将参数发送到测量分析模块)
emit saveToMeasurementRequested(m_currentFilePath);
}
void DeviceParameterConfig::onSetColumnButtonClicked()
{
m_configView->showColumnControlDialog();
}
bool DeviceParameterConfig::createDefaultConfigFile(const QString &filePath)
{
// 创建默认配置文件(含 32 个通道)
QJsonObject rootObj;
rootObj["command"] = "SET";
QJsonArray channelsArray;
QJsonObject defaultChannel;
defaultChannel["eTransferModel"] = "eSpecturmMode";
defaultChannel["iDeviceGain"] = 1;
defaultChannel["iDeviceGainSelectIndex"] = 1;
defaultChannel["iSoftGain"] = 3000;
defaultChannel["dConstTime"] = 45.0;
defaultChannel["iFormTime"] = 3;
defaultChannel["iFastChannelTrigerValue"] = 10.0;
defaultChannel["iChannelNum"] = 1024;
defaultChannel["iHighVoltage"] = 0;
defaultChannel["iInputVoltageDesc"] = 0;
defaultChannel["iCRDivMode"] = 0;
defaultChannel["iInputSignalPostive"] = 0;
defaultChannel["iCurrentOffset"] = 0;
defaultChannel["iMaxEnergy"] = 0;
defaultChannel["iAMPeakDiv"] = 0;
defaultChannel["iHVDelt"] = 0;
defaultChannel["iHVCtrl"] = 0;
defaultChannel["iGetSpecturmPeirod"] = 1;
defaultChannel["iTotalMeasureTime"] = 10;
defaultChannel["iTotalMeasureCount"] = 1;
defaultChannel["iTrapeTopShitBit"] = 0;
defaultChannel["iRiseTime"] = 2;
defaultChannel["iTopTime"] = 2;
defaultChannel["bICRCorrect"] = false;
defaultChannel["iCRZAValue"] = 0;
defaultChannel["iZAEnable"] = 30;
defaultChannel["reserve"] = QJsonArray();
defaultChannel["pUserConfigInfo"] = QJsonObject();
for (int i = 0; i < 32; ++i) {
channelsArray.append(defaultChannel);
}
rootObj["channels"] = channelsArray;
rootObj["remark"] = "";
QJsonDocument doc(rootObj);
QFile file(filePath);
if (!file.open(QIODevice::WriteOnly))
return false;
file.write(doc.toJson());
file.close();
return true;
}

View File

@ -1,73 +0,0 @@
#ifndef DEVICEPARAMETERCONFIG_H
#define DEVICEPARAMETERCONFIG_H
#include <QWidget>
#include <QHash>
class DeviceParameterConfigList;
class DeviceConfigView;
class QLineEdit;
class QTextEdit;
class QCheckBox;
class QPushButton;
class DeviceParameterConfig : public QWidget
{
Q_OBJECT
public:
explicit DeviceParameterConfig(QWidget *parent = nullptr);
~DeviceParameterConfig();
void setColumnMapping(const QHash<QString, QString> &mapping);
bool loadConfig(const QString &filePath);
bool saveCurrentConfig();
QString getCurrentFileName() const;
QString getRemark() const;
void setRemark(const QString &remark);
signals:
void saveToMeasurementRequested(const QString &filePath);
void configLoaded(QString );
private slots:
void onConfigSelected(const QString &filePath);
void onConfigDeleted(const QString &fileName);
void onCreateNewConfigRequested(const QString &fileName);
void onSaveButtonClicked();
void onSetColumnButtonClicked();
private:
void setupUi();
bool createDefaultConfigFile(const QString &filePath);
void initColumnMapping(); // 初始化默认映射(若外部未调用则使用默认)
// 子控件
DeviceParameterConfigList *m_configList;
DeviceConfigView *m_configView;
// 周边控件
QLineEdit *m_lineEditFileName;
QTextEdit *m_textEditRemark;
QCheckBox *m_checkBoxSaveToDevice;
QPushButton *m_btnSave;
QPushButton *m_btnSetColumn;
QString m_currentFilePath;
QHash<QString, QString> m_columnToJsonKey; // 列头->JSON键映射
};
#endif // DEVICEPARAMETERCONFIG_H

View File

@ -1,214 +0,0 @@
#include "DeviceParameterConfigList.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QListWidget>
#include <QPushButton>
#include <QDir>
#include <QFile>
#include <QInputDialog>
#include <QMessageBox>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QDebug>
#include <QDateTime>
#include <QLabel>
DeviceParameterConfigList::DeviceParameterConfigList(QWidget *parent)
: QWidget(parent)
, m_listWidget(nullptr)
, m_btnAdd(nullptr)
, m_btnDelete(nullptr)
{
setupUi();
}
DeviceParameterConfigList::~DeviceParameterConfigList()
{
}
void DeviceParameterConfigList::setupUi()
{
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins(0, 0, 0, 0);
QLabel *ListWidgetName = new QLabel(QStringLiteral(u"设备参数配置列表"));
mainLayout->addWidget(ListWidgetName);
m_listWidget = new QListWidget(this);
mainLayout->addWidget(m_listWidget);
QHBoxLayout *btnLayout = new QHBoxLayout();
m_btnAdd = new QPushButton(QStringLiteral(u"添加"), this);
m_btnDelete = new QPushButton(QStringLiteral(u"删除"), this);
btnLayout->addWidget(m_btnAdd);
btnLayout->addWidget(m_btnDelete);
btnLayout->addStretch();
mainLayout->addLayout(btnLayout);
connect(m_listWidget, &QListWidget::itemClicked, this, &DeviceParameterConfigList::onItemClicked);
connect(m_btnAdd, &QPushButton::clicked, this, &DeviceParameterConfigList::onAddClicked);
connect(m_btnDelete, &QPushButton::clicked, this, &DeviceParameterConfigList::onDeleteClicked);
}
void DeviceParameterConfigList::loadConfigsFromFolder(const QString &folderPath)
{
if (folderPath.isEmpty()) {
m_folderPath = QDir::currentPath() + "/parameterConfig";
} else {
m_folderPath = folderPath;
}
QDir dir(m_folderPath);
if (!dir.exists()) {
dir.mkpath(m_folderPath);
}
dir.setFilter(QDir::Files | QDir::NoDotAndDotDot);
QStringList files = dir.entryList();
updateList(files);
}
void DeviceParameterConfigList::updateList(const QStringList &fileList)
{
m_listWidget->clear();
for (const QString &file : fileList) {
if (file.endsWith(".json", Qt::CaseInsensitive)) {
m_listWidget->addItem(file);
}
}
}
QString DeviceParameterConfigList::getCurrentFilePath() const
{
QListWidgetItem *item = m_listWidget->currentItem();
if (!item) return QString();
return m_folderPath + "/" + item->text();
}
QString DeviceParameterConfigList::getCurrentFileName() const
{
QListWidgetItem *item = m_listWidget->currentItem();
return item ? item->text() : QString();
}
void DeviceParameterConfigList::setCurrentFile(const QString &fileName)
{
QList<QListWidgetItem*> items = m_listWidget->findItems(fileName, Qt::MatchExactly);
if (!items.isEmpty()) {
m_listWidget->setCurrentItem(items.first());
emit configSelected(getCurrentFilePath());
}
}
void DeviceParameterConfigList::refresh()
{
loadConfigsFromFolder(m_folderPath);
}
void DeviceParameterConfigList::onItemClicked(QListWidgetItem *item)
{
if (item) {
emit configSelected(m_folderPath + "/" + item->text());
}
}
void DeviceParameterConfigList::onAddClicked()
{
bool ok;
QString fileName = QInputDialog::getText(this, QStringLiteral(u"新建配置"),
QStringLiteral(u"请输入配置文件名(无需后缀):"),
QLineEdit::Normal,
QString("NewConfig_%1").arg(QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss")),
&ok);
if (!ok || fileName.isEmpty()) return;
if (!fileName.endsWith(".json", Qt::CaseInsensitive))
fileName += ".json";
QString filePath = m_folderPath + "/" + fileName;
if (QFile::exists(filePath)) {
QMessageBox::warning(this, QStringLiteral(u"错误"), QStringLiteral(u"文件已存在,请使用其他名称。"));
return;
}
// 发出创建请求,由外部(主窗口)决定默认内容
emit createNewConfigRequested(fileName);
}
void DeviceParameterConfigList::onDeleteClicked()
{
QListWidgetItem *currentItem = m_listWidget->currentItem();
if (!currentItem) {
QMessageBox::information(this, QStringLiteral(u"提示"), QStringLiteral(u"请先选择要删除的配置文件。"));
return;
}
QString fileName = currentItem->text();
QString filePath = m_folderPath + "/" + fileName;
int ret = QMessageBox::question(this, QStringLiteral(u"确认删除"),
QStringLiteral(u"确定要删除文件 \"%1\" 吗?").arg(fileName),
QMessageBox::Yes | QMessageBox::No);
if (ret != QMessageBox::Yes) return;
QFile file(filePath);
if (file.remove()) {
delete currentItem;
emit configDeleted(fileName);
QMessageBox::information(this, QStringLiteral(u"成功"), QStringLiteral(u"文件已删除。"));
} else {
QMessageBox::warning(this, QStringLiteral(u"错误"), QStringLiteral(u"无法删除文件:%1").arg(file.errorString()));
}
}
bool DeviceParameterConfigList::createDefaultConfigFile(const QString &filePath)
{
// 默认配置内容(与原来保持一致)
QJsonObject rootObj;
rootObj["command"] = "SET";
QJsonArray channelsArray;
QJsonObject defaultChannel;
defaultChannel["eTransferModel"] = "eSpecturmMode";
defaultChannel["iDeviceGain"] = 1;
defaultChannel["iDeviceGainSelectIndex"] = 1;
defaultChannel["iSoftGain"] = 3000;
defaultChannel["dConstTime"] = 45.0;
defaultChannel["iFormTime"] = 3;
defaultChannel["iFastChannelTrigerValue"] = 10.0;
defaultChannel["iChannelNum"] = 1024;
defaultChannel["iHighVoltage"] = 0;
defaultChannel["iInputVoltageDesc"] = 0;
defaultChannel["iCRDivMode"] = 0;
defaultChannel["iInputSignalPostive"] = 0;
defaultChannel["iCurrentOffset"] = 0;
defaultChannel["iMaxEnergy"] = 0;
defaultChannel["iAMPeakDiv"] = 0;
defaultChannel["iHVDelt"] = 0;
defaultChannel["iHVCtrl"] = 0;
defaultChannel["iGetSpecturmPeirod"] = 1;
defaultChannel["iTotalMeasureTime"] = 10;
defaultChannel["iTotalMeasureCount"] = 1;
defaultChannel["iTrapeTopShitBit"] = 0;
defaultChannel["iRiseTime"] = 2;
defaultChannel["iTopTime"] = 2;
defaultChannel["bICRCorrect"] = false;
defaultChannel["iCRZAValue"] = 0;
defaultChannel["iZAEnable"] = 30;
defaultChannel["reserve"] = QJsonArray();
defaultChannel["pUserConfigInfo"] = QJsonObject();
for (int i = 0; i < 32; ++i) {
channelsArray.append(defaultChannel);
}
rootObj["channels"] = channelsArray;
QJsonDocument doc(rootObj);
QFile file(filePath);
if (!file.open(QIODevice::WriteOnly)) {
return false;
}
file.write(doc.toJson());
file.close();
return true;
}

View File

@ -1,56 +0,0 @@
#ifndef DEVICEPARAMETERCONFIGLIST_H
#define DEVICEPARAMETERCONFIGLIST_H
#include <QWidget>
#include <QListWidgetItem>
class QListWidget;
class QPushButton;
class DeviceParameterConfigList : public QWidget
{
Q_OBJECT
public:
explicit DeviceParameterConfigList(QWidget *parent = nullptr);
~DeviceParameterConfigList();
void loadConfigsFromFolder(const QString &folderPath = QString());
QString getCurrentFilePath() const;
QString getCurrentFileName() const;
void setCurrentFile(const QString &fileName);
void refresh();
signals:
void configSelected(const QString &filePath);
void configDeleted(const QString &fileName);
void createNewConfigRequested(const QString &fileName);
private slots:
void onItemClicked(QListWidgetItem *item);
void onAddClicked();
void onDeleteClicked();
private:
void setupUi();
void updateList(const QStringList &fileList);
bool createDefaultConfigFile(const QString &filePath);
QListWidget *m_listWidget;
QPushButton *m_btnAdd;
QPushButton *m_btnDelete;
QString m_folderPath;
};
#endif // DEVICEPARAMETERCONFIGLIST_H

View File

@ -1,384 +0,0 @@
#include "DeviceParameterProxy.h"
#include <QComboBox>
#include <QDoubleSpinBox>
#include <QSpinBox>
#include <QLineEdit>
#include <QToolTip>
#include <QTimer>
#include <QKeyEvent>
#include <QMessageBox>
#include <QRegularExpressionValidator>
#include <QDebug>
DeviceParameterProxy::DeviceParameterProxy(QObject *parent) : QStyledItemDelegate(parent)
{
}
QWidget* DeviceParameterProxy::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
int col = index.column();
switch (col)
{
case 0: // 数据传输模式(枚举)
{
QComboBox *combo = new QComboBox(parent);
combo->addItems(QStringList() << QStringLiteral(u"谱线模式") << QStringLiteral(u"波形模式") << QStringLiteral(u"ADC模式") << QStringLiteral(u"列表模式") << QStringLiteral(u"α/β模式"));
return combo;
}
case 1: // 硬件增益(档位)
{
QComboBox *combo = new QComboBox(parent);
combo->addItems(QStringList() << QStringLiteral(u"1") << QStringLiteral(u"2") << QStringLiteral(u"4") << QStringLiteral(u"8") << QStringLiteral(u"16"));
return combo;
}
case 2: // 硬件增益选择索引
{
QComboBox *combo = new QComboBox(parent);
combo->addItems(QStringList() << QStringLiteral(u"1") << QStringLiteral(u"2") << QStringLiteral(u"3") << QStringLiteral(u"4") << QStringLiteral(u"5"));
return combo;
}
case 3: // 软件增益32位无符号
{
QLineEdit *edit = new QLineEdit(parent);
edit->setValidator(new UInt32Validator(edit));
edit->setProperty("rangeHint", "0 ~ 4294967295");
edit->installEventFilter(const_cast<DeviceParameterProxy*>(this));
return edit;
}
case 4: // 时间常数double μs
{
QDoubleSpinBox *spin = new QDoubleSpinBox(parent);
spin->setRange(0.0, 1000.0);
spin->setSingleStep(1.0);
spin->setDecimals(2);
return spin;
}
case 5: // 成形时间int μs
{
QSpinBox *spin = new QSpinBox(parent);
spin->setRange(1, 10);
return spin;
}
case 6: // 快通道触发阈值double 0.1mV
{
QDoubleSpinBox *spin = new QDoubleSpinBox(parent);
spin->setRange(0.0, 10000.0);
spin->setSingleStep(0.1);
spin->setDecimals(1);
return spin;
}
case 7: // 多道分辨率2的幂
{
QComboBox *combo = new QComboBox(parent);
combo->addItems(QStringList() << QStringLiteral(u"256") << QStringLiteral(u"512") << QStringLiteral(u"1024") << QStringLiteral(u"2048") << QStringLiteral(u"4096") << QStringLiteral(u"8192") << QStringLiteral(u"16384"));
return combo;
}
case 8: // 控制功能(位掩码,暂用十进制输入)
{
QLineEdit *edit = new QLineEdit(parent);
// 允许输入十进制数字,不设范围限制(业务层处理)
return edit;
}
case 9: // 幅度提前延迟unsigned char
{
QSpinBox *spin = new QSpinBox(parent);
spin->setRange(0, 255);
return spin;
}
case 10: // 积分长度unsigned char
{
QSpinBox *spin = new QSpinBox(parent);
spin->setRange(0, 255);
return spin;
}
case 11: // dcfd缩放倍数unsigned char
{
QSpinBox *spin = new QSpinBox(parent);
spin->setRange(0, 255);
return spin;
}
case 12: // dcfd延迟unsigned char
{
QSpinBox *spin = new QSpinBox(parent);
spin->setRange(0, 255);
return spin;
}
case 13: // 直流偏移mV
{
QSpinBox *spin = new QSpinBox(parent);
spin->setRange(-1000, 1000);
return spin;
}
case 14: // 最大能量范围keV
{
QSpinBox *spin = new QSpinBox(parent);
spin->setRange(0, 99999);
return spin;
}
case 15: // Am峰面积寻峰法的面积比例%
{
QSpinBox *spin = new QSpinBox(parent);
spin->setRange(0, 100);
return spin;
}
case 16: // K40与Am241的峰位校正系数short
{
QSpinBox *spin = new QSpinBox(parent);
spin->setRange(-32768, 32767);
return spin;
}
case 17: // 高压关断阈值short
{
QSpinBox *spin = new QSpinBox(parent);
spin->setRange(-32768, 32767);
return spin;
}
case 18: // 获取能谱周期(秒)
{
QSpinBox *spin = new QSpinBox(parent);
spin->setRange(0, 86400); // 一天
return spin;
}
case 19: // 总测量时间__int6464位
{
QLineEdit *edit = new QLineEdit(parent);
edit->setValidator(new Int64Validator(edit));
edit->setProperty("rangeHint", "0 ~ 9223372036854775807");
edit->installEventFilter(const_cast<DeviceParameterProxy*>(this));
return edit;
}
case 20: // 总测量次数
{
QSpinBox *spin = new QSpinBox(parent);
spin->setRange(0, 1000000); // 可调大
return spin;
}
case 21: // 滤波参数
{
QSpinBox *spin = new QSpinBox(parent);
spin->setRange(0, 3);
return spin;
}
case 22: // 上升时间μs
{
QSpinBox *spin = new QSpinBox(parent);
spin->setRange(1, 255);
return spin;
}
case 23: // 平顶时间μs
{
QSpinBox *spin = new QSpinBox(parent);
spin->setRange(1, 255);
return spin;
}
case 24: // ICR校正使能布尔
{
QComboBox *combo = new QComboBox(parent);
combo->addItems(QStringList() << QStringLiteral(u"关闭") << QStringLiteral(u"启用"));
return combo;
}
case 25: // CRZA值
{
QSpinBox *spin = new QSpinBox(parent);
spin->setRange(0, 1000000); // 合理范围
return spin;
}
case 26: // ZA使能值
{
QSpinBox *spin = new QSpinBox(parent);
spin->setRange(0, 100);
return spin;
}
default:
return new QLineEdit(parent);
}
}
void DeviceParameterProxy::setEditorData(QWidget *editor, const QModelIndex &index) const
{
QVariant value = index.data(Qt::EditRole);
int col = index.column();
switch (col)
{
case 0: // QComboBox
case 1:
case 2:
case 7:
case 24:
{
QComboBox *combo = qobject_cast<QComboBox*>(editor);
if (combo) {
int idx = combo->findText(value.toString());
if (idx >= 0) combo->setCurrentIndex(idx);
}
break;
}
case 3: // QLineEdit软件增益
case 8: // QLineEdit控制功能
case 19: // QLineEdit总测量时间
{
QLineEdit *edit = qobject_cast<QLineEdit*>(editor);
if (edit) edit->setText(value.toString());
break;
}
case 4: // QDoubleSpinBox
case 6:
{
QDoubleSpinBox *spin = qobject_cast<QDoubleSpinBox*>(editor);
if (spin) spin->setValue(value.toDouble());
break;
}
case 5: // QSpinBox
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
case 16:
case 17:
case 18:
case 20:
case 21:
case 22:
case 23:
case 25:
case 26:
{
QSpinBox *spin = qobject_cast<QSpinBox*>(editor);
if (spin) spin->setValue(value.toInt());
break;
}
default:
{
QLineEdit *edit = qobject_cast<QLineEdit*>(editor);
if (edit) edit->setText(value.toString());
break;
}
}
}
void DeviceParameterProxy::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
int col = index.column();
switch (col)
{
case 0:
case 1:
case 2:
case 7:
case 24:
{
QComboBox *combo = qobject_cast<QComboBox*>(editor);
if (combo) model->setData(index, combo->currentText());
break;
}
case 3: // 软件增益字符串存储因为可能超出int范围
case 8: // 控制功能(字符串存储)
case 19: // 总测量时间(字符串存储)
{
QLineEdit *edit = qobject_cast<QLineEdit*>(editor);
// if (edit) model->setData(index, edit->text());
if (edit) {
// 提交前再次验证(防止通过回车提交无效数据)
QString text = edit->text();
int pos = 0;
if (edit->validator() && edit->validator()->validate(text, pos) == QValidator::Acceptable) {
model->setData(index, text);
} else {
// 无效数据不写入模型,并显示提示
QString rangeHint = edit->property("rangeHint").toString();
QPoint pos = edit->mapToGlobal(edit->rect().topRight());
QToolTip::showText(pos, QString("取值范围: %1").arg(rangeHint), edit);
// 焦点留在编辑器(但此时编辑器即将销毁,所以需要延迟重新打开?)
// 实际上 setModelData 被调用时编辑器即将销毁,我们无法阻止。
// 因此更好的方法是在事件过滤器中拦截回车,避免走到这里。
}
}
break;
}
case 4:
case 6:
{
QDoubleSpinBox *spin = qobject_cast<QDoubleSpinBox*>(editor);
if (spin) model->setData(index, spin->value());
break;
}
case 5:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
case 16:
case 17:
case 18:
case 20:
case 21:
case 22:
case 23:
case 25:
case 26:
{
QSpinBox *spin = qobject_cast<QSpinBox*>(editor);
if (spin) model->setData(index, spin->value());
break;
}
default:
{
QLineEdit *edit = qobject_cast<QLineEdit*>(editor);
if (edit) model->setData(index, edit->text());
break;
}
}
}
void DeviceParameterProxy::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
editor->setGeometry(option.rect);
}
bool DeviceParameterProxy::eventFilter(QObject *obj, QEvent *event)
{
QLineEdit *edit = qobject_cast<QLineEdit*>(obj);
if (!edit || !edit->validator())
return QStyledItemDelegate::eventFilter(obj, event);
if (event->type() == QEvent::FocusOut) {
QString text = edit->text();
int pos = 0;
if (edit->validator()->validate(text, pos) != QValidator::Acceptable) {
QString rangeHint = edit->property("rangeHint").toString();
QPoint pos = edit->mapToGlobal(edit->rect().topRight());
QToolTip::showText(pos, QStringLiteral(u"取值范围: %1").arg(rangeHint), edit);
// 延迟重新获得焦点
QTimer::singleShot(0, edit, SLOT(setFocus()));
return true; // 阻止焦点离开
} else {
QToolTip::hideText();
}
}
else if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) {
QString text = edit->text();
int pos = 0;
if (edit->validator()->validate(text, pos) != QValidator::Acceptable) {
QString rangeHint = edit->property("rangeHint").toString();
QPoint pos = edit->mapToGlobal(edit->rect().topRight());
QToolTip::showText(pos, QStringLiteral(u"取值范围: %1").arg(rangeHint), edit);
return true; // 拦截回车,不提交
} else {
QToolTip::hideText();
// 允许回车提交Qt 会正常处理
}
}
}
return QStyledItemDelegate::eventFilter(obj, event);
}

View File

@ -1,119 +0,0 @@
#ifndef DEVICEPARAMETERPROXY_H
#define DEVICEPARAMETERPROXY_H
#include <QStyledItemDelegate>
#include <QIntValidator>
#include <QLineEdit>
// ==================== 自定义验证器 ====================
/**
* @brief 32 0 ~ 4294967295
*/
class UInt32Validator : public QValidator
{
public:
UInt32Validator(QObject *parent = nullptr) : QValidator(parent) {}
State validate(QString &input, int &pos) const override
{
if (input.isEmpty())
return Intermediate;
bool ok;
quint64 value = input.toULongLong(&ok);
if (!ok)
return Invalid;
if (value <= 4294967295ULL)
return Acceptable;
return Invalid;
}
void fixup(QString &input) const override
{
input.clear();
}
};
/**
* @brief 64 0 ~ 9223372036854775807
* __int64
*/
class Int64Validator : public QValidator
{
public:
Int64Validator(QObject *parent = nullptr) : QValidator(parent) {}
State validate(QString &input, int &pos) const override
{
if (input.isEmpty())
return Intermediate;
bool ok;
qint64 value = input.toLongLong(&ok);
if (!ok)
return Invalid;
if (value >= 0 && value <= 9223372036854775807LL)
return Acceptable;
return Invalid;
}
void fixup(QString &input) const override
{
input.clear();
}
};
/**
* @brief
*
*
*/
class DeviceParameterProxy : public QStyledItemDelegate
{
Q_OBJECT
public:
explicit DeviceParameterProxy(QObject *parent = nullptr);
/**
* @brief
* @param parent
* @param option
* @param index
* @return
*/
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
/**
* @brief
* @param editor
* @param index
*/
void setEditorData(QWidget *editor, const QModelIndex &index) const override;
/**
* @brief
* @param editor
* @param model
* @param index
*/
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
/**
* @brief
* @param editor
* @param option
* @param index
*/
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
protected:
bool eventFilter(QObject *obj, QEvent *event) override; // 事件过滤器,用于验证输入和显示提示
};
#endif // DEVICEPARAMETERPROXY_H

View File

@ -1,37 +1,35 @@
#define NOMINMAX
//#include <locale>
#include <vector>
#include <algorithm>
// #include <locale>
#include "EnergyCountPeakFitView.h"
#include "CustomQwtPlot.h"
#include "PlotRectItem.h"
#include "csv.h"
#include <GlobalDefine.h>
#include <QCheckBox>
#include <QDebug>
#include <QDialog>
#include <QFileInfo>
#include <QHBoxLayout>
#include <QInputDialog>
#include <QMenu>
#include <QPushButton>
#include <QwtLegend>
#include <QwtPlotCanvas>
#include <QwtPlotCurve>
#include <QwtPlotMarker>
#include <QwtScaleDiv>
#include <QwtScaleMap>
#include <QwtText>
#include <QDialog>
#include <QPushButton>
#include <QCheckBox>
#include <QwtScaleDiv>
#include <QFileInfo>
#include "PlotRectItem.h"
#include <QInputDialog>
#include <QDebug>
#include <algorithm>
#include <vector>
#include <QMessageBox>
#include <QListWidget>
#include <QDateTime>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QDir>
#include "MeasureAnalysisProjectModel.h"
#include <QDateTime>
#include <QDir>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QListWidget>
#include <QMessageBox>
QJsonObject PeakFitHistoryItem::toJson() const
{
@ -67,7 +65,7 @@ PeakFitHistoryItem PeakFitHistoryItem::fromJson(const QJsonObject& obj)
return item;
}
EnergyCountPeakFitView::EnergyCountPeakFitView(QWidget *parent)
EnergyCountPeakFitView::EnergyCountPeakFitView(QWidget* parent)
: MeasureAnalysisView { parent }
{
this->setViewType(PlotFrame);
@ -84,29 +82,31 @@ EnergyCountPeakFitView::~EnergyCountPeakFitView()
{
LOG_DEBUG(QStringLiteral(u"%1析构.").arg(this->GetViewName()));
delete _rubberBand;
clearAllSelectionRects();
clearFitCurves();
clearAllSelectionRects();
clearFitCurves();
}
void EnergyCountPeakFitView::InitViewWorkspace(const QString &project_name)
void EnergyCountPeakFitView::InitViewWorkspace(const QString& project_name)
{
Q_UNUSED(project_name);
if (project_name.isEmpty()) return;
auto project_model = ProjectList::Instance()->GetProjectModel(project_name);
if (!project_model) return;
if (project_name.isEmpty())
return;
auto project_model = ProjectList::Instance()->GetProjectModel(project_name);
if (!project_model)
return;
QDir project_dir(project_model->GetProjectDir());
_workspace = project_dir.filePath(this->GetViewName());
if (!QDir(_workspace).exists())
project_dir.mkpath(_workspace);
QDir project_dir(project_model->GetProjectDir());
_workspace = project_dir.filePath(this->GetViewName());
if (!QDir(_workspace).exists())
project_dir.mkpath(_workspace);
_historyFilePath = QDir(_workspace).filePath("peak_fit_history.json");
loadHistoryFromFile();
_historyFilePath = QDir(_workspace).filePath("peak_fit_history.json");
loadHistoryFromFile();
}
void EnergyCountPeakFitView::SetAnalyzeDataFilename(const QMap<QString, QVariant> &data_files_set)
void EnergyCountPeakFitView::SetAnalyzeDataFilename(const QMap<QString, QVariant>& data_files_set)
{
if ( !data_files_set.isEmpty() ) {
if (!data_files_set.isEmpty()) {
const QString& data_name = data_files_set.firstKey();
const QString& data_filename = data_files_set.first().toString();
if (QFileInfo(data_filename).exists()) {
@ -138,9 +138,9 @@ void EnergyCountPeakFitView::setupPlot()
_plot->enableAxis(QwtPlot::yLeft);
// 设置QWT图例
QwtLegend* legend = new QwtLegend();
legend->setDefaultItemMode(QwtLegendData::ReadOnly);
_plot->insertLegend(legend, QwtPlot::RightLegend);
QwtLegend* legend = new QwtLegend();
legend->setDefaultItemMode(QwtLegendData::ReadOnly);
_plot->insertLegend(legend, QwtPlot::RightLegend);
_plot->SetAxisDragScale(QwtPlot::xBottom, true);
@ -150,9 +150,6 @@ void EnergyCountPeakFitView::setupPlot()
// 启用鼠标追踪,并安装事件过滤器
_plot->canvas()->setMouseTracking(true);
_plot->canvas()->installEventFilter(this);
}
void EnergyCountPeakFitView::setupMenu()
@ -178,25 +175,25 @@ void EnergyCountPeakFitView::setupMenu()
QAction* action_clear_rect = this->_menu->addAction(QStringLiteral(u"清除框选标记"));
connect(action_clear_rect, &QAction::triggered, this, &EnergyCountPeakFitView::clearAllSelectionRects);
// this->_menu->addSeparator();
// QAction* action_select_algorithm = this->_menu->addAction(QStringLiteral(u"选择拟合算法"));
// this->_menu->addSeparator();
// QAction* action_select_algorithm = this->_menu->addAction(QStringLiteral(u"选择拟合算法"));
QAction* action_clear_fit = this->_menu->addAction(QStringLiteral(u"清除拟合曲线"));
connect(action_clear_fit, &QAction::triggered, this, &EnergyCountPeakFitView::clearFitCurves);
connect(action_clear_fit, &QAction::triggered, this, &EnergyCountPeakFitView::clearFitCurves);
// [NEW] 保存当前拟合结果
QAction* action_save_fit = this->_menu->addAction(QStringLiteral(u"保存当前拟合结果"));
connect(action_save_fit, &QAction::triggered, this, &EnergyCountPeakFitView::onActionSaveCurrentFit);
// [NEW] 保存当前拟合结果
QAction* action_save_fit = this->_menu->addAction(QStringLiteral(u"保存当前拟合结果"));
connect(action_save_fit, &QAction::triggered, this, &EnergyCountPeakFitView::onActionSaveCurrentFit);
// [NEW] 查看历史拟合结果
QAction* action_show_history = this->_menu->addAction(QStringLiteral(u"峰拟合结果"));
connect(action_show_history, &QAction::triggered, this, &EnergyCountPeakFitView::onActionShowFitHistory);
// [NEW] 查看历史拟合结果
QAction* action_show_history = this->_menu->addAction(QStringLiteral(u"峰拟合结果"));
connect(action_show_history, &QAction::triggered, this, &EnergyCountPeakFitView::onActionShowFitHistory);
QAction* action_hint = this->_menu->addAction(QStringLiteral(u"框选提示:按住 Ctrl 键并拖动左键"));
action_hint->setEnabled(false);
}
void EnergyCountPeakFitView::loadDataFromFile(const QString &data_name, const QString &filename)
void EnergyCountPeakFitView::loadDataFromFile(const QString& data_name, const QString& filename)
{
std::string address_str = QString(QStringLiteral(u"能量(KeV)")).toStdString();
std::string count_str = QString(QStringLiteral(u"计数")).toStdString();
@ -220,7 +217,7 @@ void EnergyCountPeakFitView::loadDataFromFile(const QString &data_name, const QS
// 绘制曲线
QwtPlotCurve* curve = new QwtPlotCurve(QStringLiteral(u"原始数据"));
curve->setSamples(x, y);
curve->setPen(QPen(Qt::red, 2)); // 原始数据统一红色
curve->setPen(QPen(Qt::red, 2)); // 原始数据统一红色
_plot->AddCurve(curve);
}
@ -246,7 +243,7 @@ void EnergyCountPeakFitView::onActionCurveShowSetting()
QVBoxLayout* checkbox_layout = new QVBoxLayout();
QHBoxLayout* checkbox_column_layout = new QHBoxLayout();
QMap<QwtPlotCurve*, QCheckBox*> curve_checkbox_map;
auto addCurveToLayout = [&](const QString& curve_name){
auto addCurveToLayout = [&](const QString& curve_name) {
QwtPlotCurve* curve = this->_plot->GetCurve(curve_name);
QCheckBox* check_box = new QCheckBox(curve->title().text());
check_box->setChecked(curve->isVisible());
@ -302,50 +299,44 @@ void EnergyCountPeakFitView::onActionCurveShowSetting()
void EnergyCountPeakFitView::onActionPlotConfigure()
{
}
void EnergyCountPeakFitView::clearAllSelectionRects()
{
for (PlotRectItem* item : _selectionRectItems) {
if (item) {
item->detach();
delete item;
}
}
_selectionRectItems.clear();
_plot->replot();
if (item) {
item->detach();
delete item;
}
}
_selectionRectItems.clear();
_plot->replot();
}
bool EnergyCountPeakFitView::eventFilter(QObject* watched, QEvent* event)
{
if (watched == _plot->canvas()) {
QMouseEvent* me = static_cast<QMouseEvent*>(event);
QMouseEvent* me = static_cast<QMouseEvent*>(event);
// 按下 Ctrl+左键 开始框选
if (event->type() == QEvent::MouseButtonPress &&
me->button() == Qt::LeftButton &&
(me->modifiers() & Qt::ControlModifier)) {
startSelection(me->pos());
// 按下 Ctrl+左键 开始框选
if (event->type() == QEvent::MouseButtonPress && me->button() == Qt::LeftButton && (me->modifiers() & Qt::ControlModifier)) {
startSelection(me->pos());
return true;
}
// 移动时更新橡皮筋
else if (event->type() == QEvent::MouseMove && _isSelecting) {
updateSelection(me->pos());
return true;
}
// 释放左键完成框选
else if (event->type() == QEvent::MouseButtonRelease &&
me->button() == Qt::LeftButton && _isSelecting) {
finishSelection();
fadeSelectionRectBorders();
return true;
}
}
return MeasureAnalysisView::eventFilter(watched, event);
return true;
}
// 移动时更新橡皮筋
else if (event->type() == QEvent::MouseMove && _isSelecting) {
updateSelection(me->pos());
return true;
}
// 释放左键完成框选
else if (event->type() == QEvent::MouseButtonRelease && me->button() == Qt::LeftButton && _isSelecting) {
finishSelection();
fadeSelectionRectBorders();
return true;
}
}
return MeasureAnalysisView::eventFilter(watched, event);
}
void EnergyCountPeakFitView::startSelection(const QPoint& pos)
@ -364,321 +355,319 @@ void EnergyCountPeakFitView::startSelection(const QPoint& pos)
void EnergyCountPeakFitView::updateSelection(const QPoint& pos)
{
if (!_rubberBand) return;
int canvasHeight = _plot->canvas()->height();
int x1 = _selectionStart.x();
int x2 = pos.x();
int left = qMin(x1, x2);
int width = qAbs(x1 - x2);
_rubberBand->setGeometry(QRect(left, 0, width, canvasHeight));
if (!_rubberBand)
return;
int canvasHeight = _plot->canvas()->height();
int x1 = _selectionStart.x();
int x2 = pos.x();
int left = qMin(x1, x2);
int width = qAbs(x1 - x2);
_rubberBand->setGeometry(QRect(left, 0, width, canvasHeight));
}
void EnergyCountPeakFitView::finishSelection()
{
if (_rubberBand)
{
QRect finalRect = _rubberBand->geometry();
_rubberBand->hide();
if (_rubberBand) {
QRect finalRect = _rubberBand->geometry();
_rubberBand->hide();
if (finalRect.width() > 2) {
const QwtScaleMap xMap = _plot->canvasMap(QwtPlot::xBottom);
double xMin = xMap.invTransform(finalRect.left());
double xMax = xMap.invTransform(finalRect.right());
if (xMin > xMax) std::swap(xMin, xMax);
if (finalRect.width() > 2) {
const QwtScaleMap xMap = _plot->canvasMap(QwtPlot::xBottom);
double xMin = xMap.invTransform(finalRect.left());
double xMax = xMap.invTransform(finalRect.right());
if (xMin > xMax)
std::swap(xMin, xMax);
double yMin = _plot->axisScaleDiv(QwtPlot::yLeft).lowerBound();
double yMax = _plot->axisScaleDiv(QwtPlot::yLeft).upperBound();
QRectF plotRect(xMin, yMin, xMax - xMin, yMax - yMin);
addSelectionRect(plotRect);
double yMin = _plot->axisScaleDiv(QwtPlot::yLeft).lowerBound();
double yMax = _plot->axisScaleDiv(QwtPlot::yLeft).upperBound();
QRectF plotRect(xMin, yMin, xMax - xMin, yMax - yMin);
addSelectionRect(plotRect);
// 获取曲线数据
QList<QwtPlotCurve*> curves = _plot->GetCurveList();
if (!curves.isEmpty()) {
QwtPlotCurve* originalCurve = curves.first();
QVector<double> origX, origY;
for (size_t i = 0; i < originalCurve->dataSize(); ++i) {
origX.push_back(originalCurve->sample(i).x());
origY.push_back(originalCurve->sample(i).y());
// 获取曲线数据
QList<QwtPlotCurve*> curves = _plot->GetCurveList();
if (!curves.isEmpty()) {
QwtPlotCurve* originalCurve = curves.first();
QVector<double> origX, origY;
for (size_t i = 0; i < originalCurve->dataSize(); ++i) {
origX.push_back(originalCurve->sample(i).x());
origY.push_back(originalCurve->sample(i).y());
}
QVector<double> roiX, roiY;
for (int i = 0; i < origX.size(); ++i) {
if (origX[i] >= xMin && origX[i] <= xMax) {
roiX.push_back(origX[i]);
roiY.push_back(origY[i]);
}
}
QVector<double> roiX, roiY;
for (int i = 0; i < origX.size(); ++i) {
if (origX[i] >= xMin && origX[i] <= xMax) {
roiX.push_back(origX[i]);
roiY.push_back(origY[i]);
if (roiX.size() >= 3) {
QStringList algorithms;
algorithms << QStringLiteral(u"光子峰拟合算法");
bool ok = false;
QString selected = QInputDialog::getItem(this,
QStringLiteral(u"选择拟合算法"),
QStringLiteral(u"请选择用于当前框选区域的峰拟合算法:"),
algorithms,
0,
false,
&ok);
if (ok && selected == QStringLiteral(u"光子峰拟合算法")) {
arma::vec armaRoiX(roiX.size()), armaRoiY(roiY.size());
for (int i = 0; i < roiX.size(); ++i) {
armaRoiX(i) = roiX[i];
armaRoiY(i) = roiY[i];
}
// 1. 自动估算默认初始参数(基于整个 ROI或取第一个峰
arma::vec defaultP0;
bool defaultValid = false;
try {
defaultP0 = EstimatePhotonPeakModelInitialParams(armaRoiX, armaRoiY);
defaultValid = true;
} catch (...) {
// 估算失败,使用硬编码默认值
}
if (!defaultValid) {
double midEnergy = (roiX.first() + roiX.last()) / 2.0;
defaultP0 = { 100.0, 2.0, 50.0, 2.0, 10.0, midEnergy };
}
// 2. 弹出参数设置对话框
FitParams defaultParams;
defaultParams.A = defaultP0(0);
defaultParams.delt = defaultP0(1);
defaultParams.H = defaultP0(2);
defaultParams.W = defaultP0(3);
defaultParams.C = defaultP0(4);
defaultParams.P = defaultP0(5);
PeakFitParamsDialog paramDlg(defaultParams, this);
if (paramDlg.exec() != QDialog::Accepted)
return; // 用户取消
FitParams userParams = paramDlg.getParams();
arma::vec userP0 = { userParams.A, userParams.delt, userParams.H,
userParams.W, userParams.C, userParams.P };
// 3. 执行拟合(曲线自动添加到主图)
QList<PeakFitResult> results = performPeakFitting(roiX, roiY, &userP0);
if (results.isEmpty()) {
qDebug() << QStringLiteral(u"拟合结果:") << QStringLiteral(u"未检测到有效峰或拟合失败。");
} else {
// QMessageBox::information(this, "拟合结果", QString("成功拟合 %1 个峰,曲线已显示在图区。").arg(results.size()));
for (const auto& r : results) {
qDebug() << QStringLiteral(u"峰中心= %1 keV, FWHM= %2, 面积= %3")
.arg(r.center)
.arg(r.fwhm)
.arg(r.area);
}
}
}
if (roiX.size() >= 3) {
QStringList algorithms;
algorithms << QStringLiteral(u"光子峰拟合算法");
bool ok = false;
QString selected = QInputDialog::getItem(this,
QStringLiteral(u"选择拟合算法"),
QStringLiteral(u"请选择用于当前框选区域的峰拟合算法:"),
algorithms,
0,
false,
&ok);
if (ok && selected == QStringLiteral(u"光子峰拟合算法")) {
arma::vec armaRoiX(roiX.size()), armaRoiY(roiY.size());
for (int i = 0; i < roiX.size(); ++i) {
armaRoiX(i) = roiX[i];
armaRoiY(i) = roiY[i];
}
// 1. 自动估算默认初始参数(基于整个 ROI或取第一个峰
arma::vec defaultP0;
bool defaultValid = false;
try {
defaultP0 = EstimatePhotonPeakModelInitialParams(armaRoiX, armaRoiY);
defaultValid = true;
} catch (...) {
// 估算失败,使用硬编码默认值
}
if (!defaultValid) {
double midEnergy = (roiX.first() + roiX.last()) / 2.0;
defaultP0 = {100.0, 2.0, 50.0, 2.0, 10.0, midEnergy};
}
// 2. 弹出参数设置对话框
FitParams defaultParams;
defaultParams.A = defaultP0(0);
defaultParams.delt = defaultP0(1);
defaultParams.H = defaultP0(2);
defaultParams.W = defaultP0(3);
defaultParams.C = defaultP0(4);
defaultParams.P = defaultP0(5);
PeakFitParamsDialog paramDlg(defaultParams, this);
if (paramDlg.exec() != QDialog::Accepted)
return; // 用户取消
FitParams userParams = paramDlg.getParams();
arma::vec userP0 = {userParams.A, userParams.delt, userParams.H,
userParams.W, userParams.C, userParams.P};
// 3. 执行拟合(曲线自动添加到主图)
QList<PeakFitResult> results = performPeakFitting(roiX, roiY, &userP0);
if (results.isEmpty()) {
qDebug()<< QStringLiteral(u"拟合结果:") << QStringLiteral(u"未检测到有效峰或拟合失败。");
} else {
// QMessageBox::information(this, "拟合结果", QString("成功拟合 %1 个峰,曲线已显示在图区。").arg(results.size()));
for (const auto& r : results) {
qDebug() << QStringLiteral(u"峰中心= %1 keV, FWHM= %2, 面积= %3")
.arg(r.center).arg(r.fwhm).arg(r.area);
}
}
}
} else {
qDebug() << QStringLiteral(u"框选区域内数据点不足3个无法拟合。");
}
} else {
qDebug() << QStringLiteral(u"框选区域内数据点不足3个无法拟合。");
}
}
}
_isSelecting = false;
}
_isSelecting = false;
}
void EnergyCountPeakFitView::addSelectionRect(const QRectF &plotRect)
void EnergyCountPeakFitView::addSelectionRect(const QRectF& plotRect)
{
PlotRectItem* rectItem = new PlotRectItem("Selection");
rectItem->setAxes(QwtPlot::xBottom, QwtPlot::yLeft);
rectItem->setRect(plotRect);
// 设置填充为透明(无填充)
rectItem->setBrush(QBrush(Qt::transparent)); // 或 Qt::NoBrush
// 设置边框颜色为红色线宽2
rectItem->setPen(QPen(Qt::red, 2));
rectItem->attach(_plot);
_selectionRectItems.append(rectItem);
_plot->replot();
rectItem->setAxes(QwtPlot::xBottom, QwtPlot::yLeft);
rectItem->setRect(plotRect);
// 设置填充为透明(无填充)
rectItem->setBrush(QBrush(Qt::transparent)); // 或 Qt::NoBrush
// 设置边框颜色为红色线宽2
rectItem->setPen(QPen(Qt::red, 2));
rectItem->attach(_plot);
_selectionRectItems.append(rectItem);
_plot->replot();
}
void EnergyCountPeakFitView::fadeSelectionRectBorders()
{
for (PlotRectItem* item : _selectionRectItems) {
if (item) {
QPen fadedPen(Qt::red, 1, Qt::DashLine); // 可根据原样式调整
QPen fadedPen(Qt::red, 1, Qt::DashLine); // 可根据原样式调整
item->setPen(fadedPen);
}
}
_plot->replot();
}
QList<PeakFitResult> EnergyCountPeakFitView::performPeakFitting(const QVector<double> &x, const QVector<double> &y, const arma::vec* userP0)
QList<PeakFitResult> EnergyCountPeakFitView::performPeakFitting(const QVector<double>& x, const QVector<double>& y, const arma::vec* userP0)
{
// 清除之前的拟合曲线(每次拟合全新绘制)
// clearFitCurves();
// clearFitCurves();
QList<PeakFitResult> results;
if (x.size() != y.size() || x.size() < 3)
{
qDebug() << QStringLiteral(u"数据长度不足");
return results;
}
if (x.size() != y.size() || x.size() < 3) {
qDebug() << QStringLiteral(u"数据长度不足");
return results;
}
// 转换为 Armadillo 向量
arma::vec armaX(x.size()), armaY(y.size());
for (int i = 0; i < x.size(); ++i) {
armaX(i) = x[i];
armaY(i) = y[i];
}
// 转换为 Armadillo 向量
arma::vec armaX(x.size()), armaY(y.size());
for (int i = 0; i < x.size(); ++i) {
armaX(i) = x[i];
armaY(i) = y[i];
}
const int step_w = 20;
if (armaY.n_elem < step_w) {
qDebug() << QStringLiteral(u"ROI 数据点太少,跳过寻峰。");
return results;
}
if (arma::all(armaY == 0)) {
qDebug() << QStringLiteral(u"ROI 计数全为零,跳过寻峰。");
return results;
}
const int step_w = 20;
if (armaY.n_elem < step_w) {
qDebug() << QStringLiteral(u"ROI 数据点太少,跳过寻峰。");
return results;
}
if (arma::all(armaY == 0)) {
qDebug() << QStringLiteral(u"ROI 计数全为零,跳过寻峰。");
return results;
}
// 构建两列矩阵:第一列为能量,第二列为计数
arma::mat spec_data(armaX.n_rows, 2);
spec_data.col(0) = armaX;
spec_data.col(1) = armaY;
// 构建两列矩阵:第一列为能量,第二列为计数
arma::mat spec_data(armaX.n_rows, 2);
spec_data.col(0) = armaX;
spec_data.col(1) = armaY;
FindPeaksBySvd peakFinder;
std::vector<FindPeaksBySvd::PeakInfo> peaks;
try {
peaks = peakFinder.FindPeaks(spec_data, step_w);
} catch (const std::string& s) {
qDebug() << QStringLiteral(u"FindPeaks 异常:") << s.c_str();
return results;
} catch (const std::exception& e) {
qDebug() << QStringLiteral(u"FindPeaks 异常:") << e.what();
return results;
} catch (...) {
qDebug() << QStringLiteral(u"FindPeaks 未知异常");
return results;
}
FindPeaksBySvd peakFinder;
std::vector<FindPeaksBySvd::PeakInfo> peaks;
try {
peaks = peakFinder.FindPeaks(spec_data, step_w);
} catch (const std::string& s) {
qDebug() << QStringLiteral(u"FindPeaks 异常:") << s.c_str();
return results;
} catch (const std::exception& e) {
qDebug() << QStringLiteral(u"FindPeaks 异常:") << e.what();
return results;
} catch (...) {
qDebug() << QStringLiteral(u"FindPeaks 未知异常");
return results;
}
if (peaks.empty()) {
qDebug() << QStringLiteral(u"未检测到峰。");
return results;
}
if (peaks.empty()) {
qDebug() << QStringLiteral(u"未检测到峰。");
return results;
}
// 选择最重要的峰(例如幅值最大的峰)
auto bestPeak = *std::max_element(peaks.begin(), peaks.end(),
[](const FindPeaksBySvd::PeakInfo& a, const FindPeaksBySvd::PeakInfo& b) {
return a.height < b.height;
});
int idxCenter = bestPeak.pos;
if (idxCenter < 0 || idxCenter >= x.size())
return results;
double centerEnergy = armaX(idxCenter);
// 选择最重要的峰(例如幅值最大的峰)
auto bestPeak = *std::max_element(peaks.begin(), peaks.end(),
[](const FindPeaksBySvd::PeakInfo& a, const FindPeaksBySvd::PeakInfo& b) {
return a.height < b.height;
});
int idxCenter = bestPeak.pos;
if (idxCenter < 0 || idxCenter >= x.size())
return results;
double centerEnergy = armaX(idxCenter);
const double fitRangeEnergy = 15.0;
// 提取局部数据
QVector<double> localX, localY;
for (int i = 0; i < x.size(); ++i) {
if (x[i] >= centerEnergy - fitRangeEnergy && x[i] <= centerEnergy + fitRangeEnergy) {
localX.push_back(x[i]);
localY.push_back(y[i]);
}
}
if (localX.size() < 5) {
qDebug() << QStringLiteral(u"局部数据点不足5跳过拟合");
return results;
}
const double fitRangeEnergy = 15.0;
// 提取局部数据
QVector<double> localX, localY;
for (int i = 0; i < x.size(); ++i) {
if (x[i] >= centerEnergy - fitRangeEnergy && x[i] <= centerEnergy + fitRangeEnergy) {
localX.push_back(x[i]);
localY.push_back(y[i]);
}
}
if (localX.size() < 5) {
qDebug() << QStringLiteral(u"局部数据点不足5跳过拟合");
return results;
}
arma::vec xLocal(localX.size()), yLocal(localY.size());
for (int i = 0; i < localX.size(); ++i) {
xLocal(i) = localX[i];
yLocal(i) = localY[i];
}
arma::vec xLocal(localX.size()), yLocal(localY.size());
for (int i = 0; i < localX.size(); ++i) {
xLocal(i) = localX[i];
yLocal(i) = localY[i];
}
arma::vec p0;
if (userP0 && userP0->n_elem == 6) {
p0 = *userP0;
} else {
try {
p0 = EstimatePhotonPeakModelInitialParams(xLocal, yLocal);
} catch (...) {
qDebug() << QStringLiteral(u"初始参数估算失败,跳过拟合");
return results;
}
}
arma::vec p0;
if (userP0 && userP0->n_elem == 6) {
p0 = *userP0;
} else {
try {
p0 = EstimatePhotonPeakModelInitialParams(xLocal, yLocal);
} catch (...) {
qDebug() << QStringLiteral(u"初始参数估算失败,跳过拟合");
return results;
}
}
arma::vec p_fit;
try {
p_fit = NolinearLeastSquaresCurveFit::Lsqcurvefit(PhotonPeakModel, xLocal, yLocal, p0);
} catch (const std::exception& e) {
qDebug() << QStringLiteral(u"拟合失败:") << e.what();
return results;
}
arma::vec p_fit;
try {
p_fit = NolinearLeastSquaresCurveFit::Lsqcurvefit(PhotonPeakModel, xLocal, yLocal, p0);
} catch (const std::exception& e) {
qDebug() << QStringLiteral(u"拟合失败:") << e.what();
return results;
}
double sigma = p_fit(1);
double fwhm = sigma * 2.355;
double sigma = p_fit(1);
double fwhm = sigma * 2.355;
AdaptiveSimpsonIntegrate::FitFunction fitFunc;
fitFunc.A = p_fit(0);
fitFunc.delt= p_fit(1);
fitFunc.H = p_fit(2);
fitFunc.W = p_fit(3);
fitFunc.C = p_fit(4);
fitFunc.P = p_fit(5);
double lower = fitFunc.P - 3.0 * fitFunc.delt;
double upper = fitFunc.P + 3.0 * fitFunc.delt;
double area = AdaptiveSimpsonIntegrate::integrate(fitFunc, lower, upper);
AdaptiveSimpsonIntegrate::FitFunction fitFunc;
fitFunc.A = p_fit(0);
fitFunc.delt = p_fit(1);
fitFunc.H = p_fit(2);
fitFunc.W = p_fit(3);
fitFunc.C = p_fit(4);
fitFunc.P = p_fit(5);
double lower = fitFunc.P - 3.0 * fitFunc.delt;
double upper = fitFunc.P + 3.0 * fitFunc.delt;
double area = AdaptiveSimpsonIntegrate::integrate(fitFunc, lower, upper);
PeakFitResult result;
result.center = p_fit(5);
result.amplitude = p_fit(0);
result.sigma = p_fit(1);
result.fwhm = fwhm;
result.area = area;
result.baseline = p_fit(4);
result.sigmoidH = p_fit(2);
result.sigmoidW = p_fit(3);
PeakFitResult result;
result.center = p_fit(5);
result.amplitude = p_fit(0);
result.sigma = p_fit(1);
result.fwhm = fwhm;
result.area = area;
result.baseline = p_fit(4);
result.sigmoidH = p_fit(2);
result.sigmoidW = p_fit(3);
double xMinPlot = result.center - 3 * result.sigma;
double xMaxPlot = result.center + 3 * result.sigma;
xMinPlot = qMax(xMinPlot, localX.first());
xMaxPlot = qMin(xMaxPlot, localX.last());
QwtPlotCurve* fitCurve = createFitCurve(result, xMinPlot, xMaxPlot, QStringLiteral(u"拟合数据"));
fitCurve->setPen(QPen(Qt::blue, 2));
_fitCurves.append(fitCurve);
double xMinPlot = result.center - 3 * result.sigma;
double xMaxPlot = result.center + 3 * result.sigma;
xMinPlot = qMax(xMinPlot, localX.first());
xMaxPlot = qMin(xMaxPlot, localX.last());
QwtPlotCurve* fitCurve = createFitCurve(result, xMinPlot, xMaxPlot, QStringLiteral(u"拟合数据"));
fitCurve->setPen(QPen(Qt::blue, 2));
_fitCurves.append(fitCurve);
results.append(result);
_plot->replot();
results.append(result);
_plot->replot();
_lastFitResult = result;
_lastFitParams = p_fit;
_lastXMin = xMinPlot;
_lastXMax = xMaxPlot;
_hasLastFit = true;
return results;
_lastFitResult = result;
_lastFitParams = p_fit;
_lastXMin = xMinPlot;
_lastXMax = xMaxPlot;
_hasLastFit = true;
return results;
}
QwtPlotCurve *EnergyCountPeakFitView::createFitCurve(const PeakFitResult &result, double xMin, double xMax, const QString &name)
QwtPlotCurve* EnergyCountPeakFitView::createFitCurve(const PeakFitResult& result, double xMin, double xMax, const QString& name)
{
const int numPoints = 200;
QVector<double> xs, ys;
double step = (xMax - xMin) / (numPoints - 1);
QVector<double> xs, ys;
double step = (xMax - xMin) / (numPoints - 1);
arma::vec p(6);
p(0) = result.amplitude;
p(1) = result.sigma;
p(2) = result.sigmoidH;
p(3) = result.sigmoidW;
p(4) = result.baseline;
p(5) = result.center;
arma::vec p(6);
p(0) = result.amplitude;
p(1) = result.sigma;
p(2) = result.sigmoidH;
p(3) = result.sigmoidW;
p(4) = result.baseline;
p(5) = result.center;
for (int i = 0; i < numPoints; ++i) {
double x = xMin + i * step;
xs.append(x);
double y = PhotonPeakModel(x, p);
ys.append(y);
}
QwtPlotCurve* curve = new QwtPlotCurve(QStringLiteral(u"拟合数据"));
curve->setPen(QPen(Qt::blue, 2));
curve->setSamples(xs, ys);
curve->attach(_plot);
return curve;
for (int i = 0; i < numPoints; ++i) {
double x = xMin + i * step;
xs.append(x);
double y = PhotonPeakModel(x, p);
ys.append(y);
}
QwtPlotCurve* curve = new QwtPlotCurve(QStringLiteral(u"拟合数据"));
curve->setPen(QPen(Qt::blue, 2));
curve->setSamples(xs, ys);
curve->attach(_plot);
return curve;
}
void EnergyCountPeakFitView::clearFitCurves()
{
for (QwtPlotCurve* curve : _fitCurves) {
@ -754,7 +743,7 @@ void EnergyCountPeakFitView::saveCurrentFitToHistory()
void EnergyCountPeakFitView::displayFitFromHistory(const PeakFitHistoryItem& item)
{
// clearFitCurves();
// clearFitCurves();
arma::vec p(6);
p(0) = item.amplitude;
@ -782,12 +771,11 @@ void EnergyCountPeakFitView::displayFitFromHistory(const PeakFitHistoryItem& ite
QwtPlotMarker* infoMarker = new QwtPlotMarker();
infoMarker->setValue(item.center, 0);
infoMarker->setLabel(QStringLiteral(u"历史峰: %1 keV\nFWHM: %2")
.arg(item.center, 0, 'f', 2)
.arg(item.fwhm, 0, 'f', 2));
.arg(item.center, 0, 'f', 2)
.arg(item.fwhm, 0, 'f', 2));
infoMarker->setLabelAlignment(Qt::AlignTop | Qt::AlignRight);
infoMarker->attach(_plot);
_plot->replot();
}
@ -812,10 +800,10 @@ void EnergyCountPeakFitView::onActionShowFitHistory()
QListWidget* listWidget = new QListWidget(&dlg);
for (const auto& item : _fitHistoryList) {
QString text = QStringLiteral(u"%1 峰中心: %2 keV FWHM: %3 面积: %4")
.arg(item.timestamp.toString("yyyy-MM-dd hh:mm:ss"))
.arg(item.center, 0, 'f', 2)
.arg(item.fwhm, 0, 'f', 2)
.arg(item.area, 0, 'f', 0);
.arg(item.timestamp.toString("yyyy-MM-dd hh:mm:ss"))
.arg(item.center, 0, 'f', 2)
.arg(item.fwhm, 0, 'f', 2)
.arg(item.area, 0, 'f', 0);
listWidget->addItem(text);
}
layout->addWidget(listWidget);

View File

@ -21,13 +21,13 @@
#include "EnergyScaleForm.h"
#include "MeasureAnalysisHistoryForm.h"
#include "MeasureAnalysisProjectModel.h"
#include "MeasureDeviceParamsCfgForm.h"
#include "NewMeasureAnalysisDlg.h"
#include "MeasureAnalysisView.h"
#include "MeasureAnalysisTreeView.h"
#include "GlobalDefine.h"
#include "DeviceParameterConfig.h"
#include "DeviceParamsManagerDlg.h"
#include "NuclideLib.h"
using namespace ads;
MainWindow* MainWindow::_s_main_win = nullptr;
@ -222,16 +222,7 @@ void MainWindow::initAction()
});
connect(ui->action_manage_measurement_analysis, &QAction::triggered, this->_action_central_dock_widget, &QAction::triggered);
connect(ui->action_device_config_mrg, &QAction::triggered, []() {
QDialog device_cfg_mrg_dlg;
device_cfg_mrg_dlg.setObjectName("MeasureDeviceParamsCfgFormDlg");
device_cfg_mrg_dlg.setWindowTitle(QStringLiteral(u"测量设备参数配置管理"));
device_cfg_mrg_dlg.setWindowFlags(device_cfg_mrg_dlg.windowFlags() | Qt::WindowMaximizeButtonHint);
// MeasureDeviceParamsCfgForm* measure_dev_params_cfg_form = new MeasureDeviceParamsCfgForm(&device_cfg_mrg_dlg);
DeviceParameterConfig * measure_dev_params_cfg_form = new DeviceParameterConfig(&device_cfg_mrg_dlg);
QHBoxLayout* hlayout = new QHBoxLayout;
hlayout->addWidget(measure_dev_params_cfg_form);
device_cfg_mrg_dlg.setLayout(hlayout);
device_cfg_mrg_dlg.exec();
DeviceParamsManagerDlg().exec();
});
connect(ui->action_energy_scale_mrg, &QAction::triggered, []() {
QDialog energy_scale_mrg_dlg;

View File

@ -46,7 +46,7 @@ void MeasureAnalysisHistoryForm::loadHistoryInfo(const QString &history_name)
if (!projects_dir.exists()) {
return;
}
QList<QString> project_dirs = projects_dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Time);
QList<QString> project_dirs = projects_dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks, QDir::Time);
for (const QString& project_dir : project_dirs) {
QDir project_dir_path(projects_dir.filePath(project_dir));
if (project_dir_path.exists()) {
@ -147,7 +147,7 @@ void MeasureAnalysisHistoryForm::onRemoveSelectedProject()
}
}
if (selected_project_list.isEmpty()) {
QMessageBox::information(this, QStringLiteral(u"确认"), QStringLiteral(u"请选择想要删除的测量分析项目!"));
QMessageBox::information(this, QStringLiteral(u"提示"), QStringLiteral(u"请选择想要删除的测量分析项目!"));
return;
}
if (QMessageBox::No == QMessageBox::question(this, QStringLiteral(u"确认"), QStringLiteral(u"是否删除选择的测量分析项目?"))) {

View File

@ -548,6 +548,7 @@ bool MeasureAnalysisProjectModelList::RmProjectModel(const QString& project_name
return false;
}
}
emit removedProjectModel(project_name);
if (_project_models.contains(project_name)) {
delete _project_models[project_name];
_project_models.remove(project_name);
@ -557,7 +558,6 @@ bool MeasureAnalysisProjectModelList::RmProjectModel(const QString& project_name
const QString& project_name = project_model->GetProjectName();
SetCurrentProjectModel(project_name);
}
emit removedProjectModel(project_name);
return true;
}

View File

@ -1,14 +0,0 @@
#include "MeasureDeviceParamsCfgForm.h"
#include "ui_MeasureDeviceParamsCfgForm.h"
MeasureDeviceParamsCfgForm::MeasureDeviceParamsCfgForm(QWidget *parent)
: QWidget(parent)
, ui(new Ui::MeasureDeviceParamsCfgForm)
{
ui->setupUi(this);
}
MeasureDeviceParamsCfgForm::~MeasureDeviceParamsCfgForm()
{
delete ui;
}

View File

@ -1,22 +0,0 @@
#ifndef MEASUREDEVICEPARAMSCFGFORM_H
#define MEASUREDEVICEPARAMSCFGFORM_H
#include <QWidget>
namespace Ui {
class MeasureDeviceParamsCfgForm;
}
class MeasureDeviceParamsCfgForm : public QWidget
{
Q_OBJECT
public:
explicit MeasureDeviceParamsCfgForm(QWidget *parent = nullptr);
~MeasureDeviceParamsCfgForm();
private:
Ui::MeasureDeviceParamsCfgForm *ui;
};
#endif // MEASUREDEVICEPARAMSCFGFORM_H

View File

@ -1,317 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MeasureDeviceParamsCfgForm</class>
<widget class="QWidget" name="MeasureDeviceParamsCfgForm">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1453</width>
<height>806</height>
</rect>
</property>
<property name="windowTitle">
<string>测量设备参数配置</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>设备参数配置列表</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QListWidget" name="listw_device_cfg">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QPushButton" name="btn_add_cfg_list_item">
<property name="text">
<string>添加</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_remove_cfg_list_item">
<property name="text">
<string>删除</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_3">
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>配置命名:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_cfg_name"/>
</item>
<item>
<widget class="QPushButton" name="btn_save_to_project">
<property name="text">
<string>保存到测量分析</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_save_to_sys">
<property name="text">
<string>保存到设备参数配置管理</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>备注说明:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing</set>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="plainTextEdit_description">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>50</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTableWidget" name="tablew_params_cfg">
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<row>
<property name="text">
<string>通道1</string>
</property>
</row>
<row>
<property name="text">
<string>通道2</string>
</property>
</row>
<row>
<property name="text">
<string>通道3</string>
</property>
</row>
<row>
<property name="text">
<string>通道4</string>
</property>
</row>
<row>
<property name="text">
<string>通道5</string>
</property>
</row>
<row>
<property name="text">
<string>通道6</string>
</property>
</row>
<row>
<property name="text">
<string>通道7</string>
</property>
</row>
<row>
<property name="text">
<string>通道8</string>
</property>
</row>
<row>
<property name="text">
<string>通道9</string>
</property>
</row>
<row>
<property name="text">
<string>通道10</string>
</property>
</row>
<row>
<property name="text">
<string>通道11</string>
</property>
</row>
<row>
<property name="text">
<string>通道12</string>
</property>
</row>
<row>
<property name="text">
<string>通道13</string>
</property>
</row>
<row>
<property name="text">
<string>通道14</string>
</property>
</row>
<row>
<property name="text">
<string>通道15</string>
</property>
</row>
<row>
<property name="text">
<string>通道16</string>
</property>
</row>
<row>
<property name="text">
<string>通道17</string>
</property>
</row>
<row>
<property name="text">
<string>通道18</string>
</property>
</row>
<row>
<property name="text">
<string>通道19</string>
</property>
</row>
<row>
<property name="text">
<string>通道20</string>
</property>
</row>
<row>
<property name="text">
<string>通道21</string>
</property>
</row>
<row>
<property name="text">
<string>通道22</string>
</property>
</row>
<column>
<property name="text">
<string>时间常数</string>
</property>
</column>
<column>
<property name="text">
<string>上升时间</string>
</property>
</column>
<column>
<property name="text">
<string>平顶时间</string>
</property>
</column>
<column>
<property name="text">
<string>触发阈值</string>
</property>
</column>
<column>
<property name="text">
<string>直流偏移</string>
</property>
</column>
<column>
<property name="text">
<string>恢复速度</string>
</property>
</column>
<column>
<property name="text">
<string>滤波参数</string>
</property>
</column>
<column>
<property name="text">
<string>输入信号正负</string>
</property>
</column>
<column>
<property name="text">
<string>LFR</string>
</property>
</column>
<column>
<property name="text">
<string>保护时间</string>
</property>
</column>
<column>
<property name="text">
<string>硬件增益</string>
</property>
</column>
<column>
<property name="text">
<string>软件增益</string>
</property>
</column>
<column>
<property name="text">
<string>谱线道数</string>
</property>
</column>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,143 @@
#include "DeviceParamsManagerDlg.h"
#include "ui_DeviceParamsManagerDlg.h"
#include <QDir>
#include "GlobalDefine.h"
#include "DeviceParamsSaveToSysDlg.h"
#include <QMessageBox>
DeviceParamsManagerDlg::DeviceParamsManagerDlg(QWidget *parent)
: QDialog(parent)
, ui(new Ui::DeviceParamsManagerDlg)
{
ui->setupUi(this);
this->setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
this->setWindowFlags(this->windowFlags() | Qt::WindowMinMaxButtonsHint);
scanParamsCfgFiles();
connect(ui->listw_cfg_list, &QListWidget::currentItemChanged, this, &DeviceParamsManagerDlg::onCfgListCurrentItemChanged);
connect(ui->btn_new, &QPushButton::clicked, this, &DeviceParamsManagerDlg::onBtnNew);
connect(ui->btn_delete, &QPushButton::clicked, this, &DeviceParamsManagerDlg::onBtnDelete);
connect(ui->btn_save, &QPushButton::clicked, this, &DeviceParamsManagerDlg::onBtnSave);
}
DeviceParamsManagerDlg::~DeviceParamsManagerDlg()
{
delete ui;
}
void DeviceParamsManagerDlg::scanParamsCfgFiles()
{
ui->params_table_form->SetButtonEnable(false);
ui->listw_cfg_list->clear();
// 遍历可执行文件目录下Projects目录下的所有文件夹找出所有项目文件夹下的.msproject文件
const QString& device_params_dir_path = QDir(qApp->applicationDirPath()).filePath("configure/DeviceParams");
QDir device_params_dir(device_params_dir_path);
if (!device_params_dir.exists(device_params_dir_path)) {
LOG_WARN(QStringLiteral(u"系统测量参数配置管理目录不存在:%1").arg(device_params_dir_path));
return;
}
QList<QString> ms_cfg_basenames = device_params_dir.entryList(QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks, QDir::Time);
for (const QString& ms_cfg_basename : ms_cfg_basenames) {
const QString& ms_cfg_filename = device_params_dir.filePath(ms_cfg_basename);
QFileInfo ms_cfg_file_info(ms_cfg_filename);
if ("mscfg" == ms_cfg_file_info.suffix()) {
QListWidgetItem* item = new QListWidgetItem(ms_cfg_file_info.baseName());
item->setData(Qt::UserRole, ms_cfg_filename);
ui->listw_cfg_list->addItem(item);
}
}
const QString cfg_name = ui->linedit_cfg_name->text();
if (!cfg_name.isEmpty()) {
QList<QListWidgetItem*> items = ui->listw_cfg_list->findItems(cfg_name, Qt::MatchExactly);
QListWidgetItem* current_item = items.first();
if (current_item) {
ui->listw_cfg_list->setCurrentItem(current_item);
}
}
}
void DeviceParamsManagerDlg::onBtnNew()
{
DeviceParamsSaveToSysDlg params_save_to_sys_dlg;
if (QDialog::Accepted == params_save_to_sys_dlg.exec()) {
const QString& device_params_dir_path = QDir(qApp->applicationDirPath()).filePath("configure/DeviceParams");
const QString cfg_name = params_save_to_sys_dlg.GetCfgName();
const QString cfg_description = params_save_to_sys_dlg.GetCfgDescription();
const QString params_cfg_filename = QDir(device_params_dir_path).filePath(cfg_name) + ".mscfg";
if (ui->params_table_form->SaveSelectedChannelConfig(params_cfg_filename, cfg_name, cfg_description)) {
QListWidgetItem* item = new QListWidgetItem(cfg_name);
item->setData(Qt::UserRole, params_cfg_filename);
ui->listw_cfg_list->addItem(item);
ui->listw_cfg_list->setCurrentItem(item);
}
}
}
void DeviceParamsManagerDlg::onBtnDelete()
{
QListWidgetItem *current = ui->listw_cfg_list->currentItem();
if (current) {
const QString& ms_cfg_filename = current->data(Qt::UserRole).toString();
if (!ms_cfg_filename.isEmpty()) {
if (QMessageBox::No == QMessageBox::question(this, QStringLiteral(u"确认"), QStringLiteral(u"是否删除选择的测量参数配置?"))) {
return;
}
QFile ms_cfg_file(ms_cfg_filename);
if (!ms_cfg_file.remove()) {
LOG_WARN(QStringLiteral(u"删除设备测量参数配置[%1]失败: %2").arg(current->text()).arg(ms_cfg_file.errorString()));
} else {
ui->listw_cfg_list->removeItemWidget(current);
ui->linedit_cfg_name->clear();
ui->pte_description->clear();
ui->params_table_form->ClearParamsTable();
}
}
}
}
void DeviceParamsManagerDlg::onBtnSave()
{
const QString& device_params_dir_path = QDir(qApp->applicationDirPath()).filePath("configure/DeviceParams");
const QString cfg_name = ui->linedit_cfg_name->text();
if (cfg_name.isEmpty()) {
QMessageBox::warning(this, QStringLiteral(u"警告"), QStringLiteral(u"测量参数配置名称不能为空!"));
return;
}
const QString cfg_description = ui->pte_description->toPlainText();
const QString cfg_filename = QDir(device_params_dir_path).filePath(cfg_name) + ".mscfg";
if (QFile::exists(cfg_filename)) {
QListWidgetItem *current = ui->listw_cfg_list->currentItem();
if (current) {
const QString& ms_cfg_filename = current->data(Qt::UserRole).toString();
if (!ms_cfg_filename.isEmpty()) {
QFile ms_cfg_file(ms_cfg_filename);
if (!ms_cfg_file.remove()) {
LOG_WARN(QStringLiteral(u"删除设备测量参数配置[%1]失败: %2").arg(current->text()).arg(ms_cfg_file.errorString()));
}
}
}
}
if (ui->params_table_form->SaveSelectedChannelConfig(cfg_filename, cfg_name, cfg_description)) {
QListWidgetItem* current = ui->listw_cfg_list->currentItem();
if (current) {
current->setText(cfg_name);
current->setData(Qt::UserRole, cfg_filename);
}
}
this->scanParamsCfgFiles();
}
void DeviceParamsManagerDlg::onCfgListCurrentItemChanged(QListWidgetItem *current)
{
if (current) {
const QString& ms_cfg_filename = current->data(Qt::UserRole).toString();
if (!ms_cfg_filename.isEmpty()) {
ui->params_table_form->SetConfigFilename(ms_cfg_filename);
ui->linedit_cfg_name->clear();
ui->pte_description->clear();
ui->linedit_cfg_name->setText(ui->params_table_form->GetConfigName());
ui->pte_description->setPlainText(ui->params_table_form->GetConfigDescription());
}
}
}

View File

@ -0,0 +1,33 @@
#ifndef DEVICEPARAMSMANAGERDLG_H
#define DEVICEPARAMSMANAGERDLG_H
#include <QDialog>
namespace Ui {
class DeviceParamsManagerDlg;
}
class QListWidgetItem;
class DeviceParamsManagerDlg : public QDialog
{
Q_OBJECT
public:
explicit DeviceParamsManagerDlg(QWidget *parent = nullptr);
~DeviceParamsManagerDlg();
private:
void scanParamsCfgFiles();
private slots:
void onBtnNew();
void onBtnDelete();
void onBtnSave();
void onCfgListCurrentItemChanged(QListWidgetItem *current);
private:
Ui::DeviceParamsManagerDlg *ui;
};
#endif // DEVICEPARAMSMANAGERDLG_H

View File

@ -0,0 +1,143 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DeviceParamsManagerDlg</class>
<widget class="QDialog" name="DeviceParamsManagerDlg">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1075</width>
<height>712</height>
</rect>
</property>
<property name="windowTitle">
<string>设备测量参数管理</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string/>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>设备测量参数配置列表</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listw_cfg_list">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="btn_new">
<property name="text">
<string>新建配置</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_delete">
<property name="text">
<string>删除配置</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string/>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>测量参数配置名称:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="linedit_cfg_name"/>
</item>
<item>
<widget class="QPushButton" name="btn_save">
<property name="text">
<string>保存</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>测量参数配置说明:</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="pte_description">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>50</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="DeviceParamsTableForm" name="params_table_form" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>DeviceParamsTableForm</class>
<extends>QWidget</extends>
<header>DeviceParamsTableForm.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,46 @@
#include "DeviceParamsSaveToSysDlg.h"
#include "ui_DeviceParamsSaveToSysDlg.h"
#include <QMessageBox>
#include <QDir>
DeviceParamsSaveToSysDlg::DeviceParamsSaveToSysDlg(QWidget *parent)
: QDialog(parent)
, ui(new Ui::DeviceParamsSaveToSysDlg)
{
ui->setupUi(this);
this->setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
connect(ui->btn_cancel, &QPushButton::clicked, this, &DeviceParamsSaveToSysDlg::reject);
connect(ui->btn_ok, &QPushButton::clicked, this, &DeviceParamsSaveToSysDlg::onBtnOkClicked);
}
DeviceParamsSaveToSysDlg::~DeviceParamsSaveToSysDlg()
{
delete ui;
}
QString DeviceParamsSaveToSysDlg::GetCfgName()
{
return ui->linedit_name->text();
}
QString DeviceParamsSaveToSysDlg::GetCfgDescription()
{
return ui->pte_description->toPlainText();
}
void DeviceParamsSaveToSysDlg::onBtnOkClicked()
{
const QString& cfg_name = ui->linedit_name->text();
if (cfg_name.isEmpty()) {
QMessageBox::warning(this, QStringLiteral(u"警告"), QStringLiteral(u"测量参数配置名称不能为空!"));
return;
}
const QString& device_params_dir_path = QDir(qApp->applicationDirPath()).filePath("configure/DeviceParams");
const QString ms_cfg_name = cfg_name + QString(".mscfg");
if (QDir(device_params_dir_path).exists(ms_cfg_name)) {
QMessageBox::warning(this, QStringLiteral(u"警告"), QStringLiteral(u"测量参数配置名称\"%1\"已存在!").arg(cfg_name));
return;
}
this->accept();
}

View File

@ -0,0 +1,28 @@
#ifndef DEVICEPARAMSSAVETOSYSDLG_H
#define DEVICEPARAMSSAVETOSYSDLG_H
#include <QDialog>
namespace Ui {
class DeviceParamsSaveToSysDlg;
}
class DeviceParamsSaveToSysDlg : public QDialog
{
Q_OBJECT
public:
explicit DeviceParamsSaveToSysDlg(QWidget *parent = nullptr);
~DeviceParamsSaveToSysDlg();
QString GetCfgName();
QString GetCfgDescription();
private slots:
void onBtnOkClicked();
private:
Ui::DeviceParamsSaveToSysDlg *ui;
};
#endif // DEVICEPARAMSSAVETOSYSDLG_H

View File

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DeviceParamsSaveToSysDlg</class>
<widget class="QDialog" name="DeviceParamsSaveToSysDlg">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>512</width>
<height>229</height>
</rect>
</property>
<property name="windowTitle">
<string>测量设备参数信息</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>测量参数配置名称:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="linedit_name"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>测量参数配置说明:</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="pte_description"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btn_ok">
<property name="text">
<string>保存到系统</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_cancel">
<property name="text">
<string>取消</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -9,6 +9,17 @@
#include <QJsonDocument>
#include <QJsonObject>
#include <QMessageBox>
#include <QDoubleSpinBox>
#include <QDir>
#include "DeviceParamsSaveToSysDlg.h"
static QStringList s_addr_count_list { "256", "512", "1024", "2048", "4096", "8192", "16384" };
static QMap<int, QString> s_transfer_mode_list {
{ 1, QStringLiteral(u"波形模式") },
{ 2, QStringLiteral(u"ADC模式") },
{ 3, QStringLiteral(u"粒子模式") }
};
static QStringList s_device_gain_list { "1", "2", "4", "8", "16" };
DeviceParamsItemDelegate::DeviceParamsItemDelegate(QObject* parent)
: QStyledItemDelegate(parent)
@ -21,52 +32,66 @@ QWidget* DeviceParamsItemDelegate::createEditor(QWidget* parent, const QStyleOpt
int col = index.column();
switch (col) {
case 1: { // 多道分辨率
QStringList value_list { "256", "512", "1024", "2048", "4096", "8192", "16384" };
QComboBox *combobox = new QComboBox(parent);
for (int index = 0; index < value_list.size(); ++index) {
QString value = value_list.at(index);
for (int index = 0; index < s_addr_count_list.size(); ++index) {
QString value = s_addr_count_list.at(index);
combobox->addItem(value);
}
editor = combobox;
} break;
case 2: { // 硬件增益
QStringList value_list { "1", "2", "4", "8", "16" };
case 2: { // 数据模式
QComboBox *combobox = new QComboBox(parent);
for (int index = 0; index < value_list.size(); ++index) {
QString value = value_list.at(index);
QList<int> transfer_mode_list = s_transfer_mode_list.keys();
qSort(transfer_mode_list.rbegin(), transfer_mode_list.rend());
foreach (int transfer_mode, transfer_mode_list) {
combobox->addItem(s_transfer_mode_list.value(transfer_mode), transfer_mode);
}
editor = combobox;
} break;
case 3: { // 硬件增益
QComboBox *combobox = new QComboBox(parent);
for (int index = 0; index < s_device_gain_list.size(); ++index) {
QString value = s_device_gain_list.at(index);
combobox->addItem(value, index + 1);
}
editor = combobox;
} break;
case 3: { // 软件增益
case 4: { // 软件增益
QSpinBox* spinbox = new QSpinBox(parent);
spinbox->setRange(1, 2^32-1);
editor = spinbox;
} break;
case 4: { // 时间常数
QSpinBox* spinbox = new QSpinBox(parent);
case 5: { // 时间常数
QDoubleSpinBox* spinbox = new QDoubleSpinBox(parent);
spinbox->setRange(1, 100);
editor = spinbox;
} break;
case 5: { // 直流偏移
case 6: { // 直流偏移
QSpinBox* spinbox = new QSpinBox(parent);
spinbox->setRange(-1000, 1000);
editor = spinbox;
} break;
case 6: { // 上升时间
case 7: { // 成形时间
QSpinBox* spinbox = new QSpinBox(parent);
spinbox->setRange(1, 255);
spinbox->setRange(1, 10);
editor = spinbox;
} break;
case 7: { // 平顶时间
QSpinBox* spinbox = new QSpinBox(parent);
spinbox->setRange(1, 255);
case 8: { // 快通道触发阈值
QDoubleSpinBox* spinbox = new QDoubleSpinBox(parent);
spinbox->setRange(0, 1000);
editor = spinbox;
} break;
case 8: { // 最大能量范围
QSpinBox* spinbox = new QSpinBox(parent);
spinbox->setRange(0, 99999);
editor = spinbox;
case 9: { // CR微分模式
QComboBox *combobox = new QComboBox(parent);
combobox->addItem(QStringLiteral(u"启用"), true);
combobox->addItem(QStringLiteral(u"禁用"), false);
editor = combobox;
} break;
case 10: { // 输入信号正负极性选择
QComboBox *combobox = new QComboBox(parent);
combobox->addItem(QStringLiteral(u"启用"), true);
combobox->addItem(QStringLiteral(u"禁用"), false);
editor = combobox;
} break;
default:
break;
@ -80,24 +105,47 @@ void DeviceParamsItemDelegate::setEditorData(QWidget* editor, const QModelIndex&
int col = index.column();
switch (col) {
case 1:
case 2: {
case 2:
case 3: {
QComboBox *combo = qobject_cast<QComboBox*>(editor);
if (combo) {
int idx = combo->findText(value.toString());
if (idx >= 0) combo->setCurrentIndex(idx);
}
} break;
case 3:
case 4:
case 5:
case 6:
case 7:
case 8: {
case 4: {
QSpinBox *spinbox = qobject_cast<QSpinBox*>(editor);
if (spinbox) {
spinbox->setValue(value.toUInt());
}
} break;
case 5: {
QDoubleSpinBox *spinbox = qobject_cast<QDoubleSpinBox*>(editor);
if (spinbox) {
spinbox->setValue(value.toDouble());
}
} break;
case 6:
case 7: {
QSpinBox *spinbox = qobject_cast<QSpinBox*>(editor);
if (spinbox) {
spinbox->setValue(value.toUInt());
}
} break;
case 8: {
QDoubleSpinBox *spinbox = qobject_cast<QDoubleSpinBox*>(editor);
if (spinbox) {
spinbox->setValue(value.toDouble());
}
} break;
case 9:
case 10: {
QComboBox *combo = qobject_cast<QComboBox*>(editor);
if (combo) {
int idx = combo->findText(value.toString());
if (idx >= 0) combo->setCurrentIndex(idx);
}
} break;
default:
break;
}
@ -108,23 +156,45 @@ void DeviceParamsItemDelegate::setModelData(QWidget* editor, QAbstractItemModel*
int col = index.column();
switch (col) {
case 1:
case 2: {
case 2:
case 3: {
QComboBox *combobox = qobject_cast<QComboBox*>(editor);
if (combobox) {
model->setData(index, combobox->currentText());
}
} break;
case 3:
case 4:
case 5:
case 6:
case 7:
case 8: {
case 4: {
QSpinBox *spinbox = qobject_cast<QSpinBox*>(editor);
if (spinbox) {
model->setData(index, spinbox->value());
}
} break;
case 5: {
QDoubleSpinBox *spinbox = qobject_cast<QDoubleSpinBox*>(editor);
if (spinbox) {
model->setData(index, spinbox->value());
}
} break;
case 6:
case 7: {
QSpinBox *spinbox = qobject_cast<QSpinBox*>(editor);
if (spinbox) {
model->setData(index, spinbox->value());
}
} break;
case 8: {
QDoubleSpinBox *spinbox = qobject_cast<QDoubleSpinBox*>(editor);
if (spinbox) {
model->setData(index, spinbox->value());
}
} break;
case 9:
case 10: {
QComboBox *combobox = qobject_cast<QComboBox*>(editor);
if (combobox) {
model->setData(index, combobox->currentText());
}
} break;
default:
break;
}
@ -171,6 +241,7 @@ DeviceParamsTableForm::DeviceParamsTableForm(QWidget* parent)
ui->params_cfg_table->setItem(row, 7, new QTableWidgetItem());
ui->params_cfg_table->setItem(row, 8, new QTableWidgetItem());
ui->params_cfg_table->setItem(row, 9, new QTableWidgetItem());
ui->params_cfg_table->setItem(row, 10, new QTableWidgetItem());
}
connect(ui->btn_all_select, &QPushButton::clicked, this, &DeviceParamsTableForm::onAllSelectBtnClicked);
@ -178,6 +249,7 @@ DeviceParamsTableForm::DeviceParamsTableForm(QWidget* parent)
connect(ui->btn_channel_select, &QPushButton::clicked, this, &DeviceParamsTableForm::onCfgChannelSelectBtnClicked);
connect(ui->btn_update_to_other, &QPushButton::clicked, this, &DeviceParamsTableForm::onCurrentChannelToOther);
connect(ui->btn_save, &QPushButton::clicked, this, &DeviceParamsTableForm::onSaveSelectedChannelConfig);
connect(ui->btn_save_to_sys, &QPushButton::clicked, this, &DeviceParamsTableForm::onSaveSelectedChannelConfigToSys);
}
DeviceParamsTableForm::~DeviceParamsTableForm()
@ -204,6 +276,18 @@ void DeviceParamsTableForm::SetConfigFilename(const QString& filename)
if (!json_doc.isObject())
return;
QVariantMap device_config_info = json_doc.object().toVariantMap();
if (device_config_info.contains(QStringLiteral(u"ParamsConfigureInfo"))) {
QVariantMap config_info = device_config_info[QStringLiteral(u"ParamsConfigureInfo")].toMap();
if (config_info.contains(QStringLiteral(u"Name"))) {
this->_cfg_name = config_info[QStringLiteral(u"Name")].toString();
}
if (config_info.contains(QStringLiteral(u"Description"))) {
this->_cfg_description = config_info[QStringLiteral(u"Description")].toString();
}
}
this->ClearParamsTable();
if (!device_config_info.contains(QStringLiteral(u"ChannelConfig")))
return;
QVariantList channel_config_list = device_config_info[QStringLiteral(u"ChannelConfig")].toList();
@ -220,31 +304,57 @@ void DeviceParamsTableForm::SetConfigFilename(const QString& filename)
int row = board_id * 4 + channel_id;
if (row >= 32)
continue;
QVariantMap channel_info;
channel_info["board_id"] = board_id;
channel_info["channel_id"] = channel_id;
ui->params_cfg_table->item(row, 0)->setData(Qt::UserRole, channel_info);
// QVariantMap channel_info;
// channel_info["board_id"] = board_id;
// channel_info["channel_id"] = channel_id;
// ui->params_cfg_table->item(row, 0)->setData(Qt::UserRole, channel_info);
if (channel_config_info.contains("AddrCount"))
ui->params_cfg_table->item(row, 1)->setText(channel_config_info["AddrCount"].toString());
if (channel_config_info.contains("TransferMode")) {
int transfer_mode = channel_config_info["TransferMode"].toInt();
ui->params_cfg_table->item(row, 2)->setText(s_transfer_mode_list.value(transfer_mode));
}
if (channel_config_info.contains("DeviceGain"))
ui->params_cfg_table->item(row, 2)->setText(channel_config_info["DeviceGain"].toString());
if (channel_config_info.contains("DeviceGainSelectIndex"))
ui->params_cfg_table->item(row, 2)->setData(Qt::UserRole, channel_config_info["DeviceGainSelectIndex"]);
ui->params_cfg_table->item(row, 3)->setText(channel_config_info["DeviceGain"].toString());
// if (channel_config_info.contains("DeviceGainSelectIndex"))
// ui->params_cfg_table->item(row, 3)->setData(Qt::UserRole, channel_config_info["DeviceGainSelectIndex"]);
if (channel_config_info.contains("SoftGain"))
ui->params_cfg_table->item(row, 3)->setText(channel_config_info["SoftGain"].toString());
ui->params_cfg_table->item(row, 4)->setText(channel_config_info["SoftGain"].toString());
if (channel_config_info.contains("TimeConst"))
ui->params_cfg_table->item(row, 4)->setText(channel_config_info["TimeConst"].toString());
ui->params_cfg_table->item(row, 5)->setText(channel_config_info["TimeConst"].toString());
if (channel_config_info.contains("DcOffset"))
ui->params_cfg_table->item(row, 5)->setText(channel_config_info["DcOffset"].toString());
if (channel_config_info.contains("RiseTime"))
ui->params_cfg_table->item(row, 6)->setText(channel_config_info["RiseTime"].toString());
if (channel_config_info.contains("FlatTime"))
ui->params_cfg_table->item(row, 7)->setText(channel_config_info["FlatTime"].toString());
if (channel_config_info.contains("MaxEnergy"))
ui->params_cfg_table->item(row, 8)->setText(channel_config_info["MaxEnergy"].toString());
ui->params_cfg_table->item(row, 6)->setText(channel_config_info["DcOffset"].toString());
if (channel_config_info.contains("FormTime"))
ui->params_cfg_table->item(row, 7)->setText(channel_config_info["FormTime"].toString());
if (channel_config_info.contains("FastChannelTrigerValue"))
ui->params_cfg_table->item(row, 8)->setText(channel_config_info["FastChannelTrigerValue"].toString());
if (channel_config_info.contains("CRDivMode")) {
bool CRDiv_mode = channel_config_info["CRDivMode"].toBool();
ui->params_cfg_table->item(row, 9)->setText(CRDiv_mode ? QStringLiteral(u"启用") : QStringLiteral(u"禁用"));
}
if (channel_config_info.contains("InputSignalPostive")) {
bool input_signal_postive = channel_config_info["InputSignalPostive"].toBool();
ui->params_cfg_table->item(row, 10)->setText(input_signal_postive ? QStringLiteral(u"启用") : QStringLiteral(u"禁用"));
}
}
}
void DeviceParamsTableForm::SetButtonEnable(bool enable)
{
ui->btn_save->setVisible(enable);
ui->btn_save_to_sys->setVisible(enable);
}
const QString &DeviceParamsTableForm::GetConfigName() const
{
return _cfg_name;
}
const QString &DeviceParamsTableForm::GetConfigDescription() const
{
return _cfg_description;
}
void DeviceParamsTableForm::onAllSelectBtnClicked()
{
for (int row = 0; row < 32; ++row) {
@ -322,14 +432,57 @@ void DeviceParamsTableForm::onCurrentChannelToOther()
for (int row = 0; row < 32; ++row) {
if (ui->params_cfg_table->isRowHidden(row))
continue;
for (int col = 1; col < ui->params_cfg_table->columnCount(); ++col) {
const QString& current_value = ui->params_cfg_table->item(current_row, col)->text();
ui->params_cfg_table->item(row, col)->setText(current_value);
if (ui->params_cfg_table->item(row, 0)->checkState() == Qt::Checked) {
for (int col = 1; col < ui->params_cfg_table->columnCount(); ++col) {
QTableWidgetItem* current_item = ui->params_cfg_table->item(current_row, col);
if (current_item) {
const QString& current_value = current_item->text();
ui->params_cfg_table->item(row, col)->setText(current_value);
}
}
}
}
}
void DeviceParamsTableForm::onSaveSelectedChannelConfig()
{
if (SaveSelectedChannelConfig(this->_config_filename, this->_cfg_name, this->_cfg_description)) {
emit deviceConfigParamsSaved(this->_config_filename);
}
}
void DeviceParamsTableForm::onSaveSelectedChannelConfigToSys()
{
int selected_channel_count = 0;
for (int row = 0; row < 32; ++row) {
if (ui->params_cfg_table->item(row, 0)->checkState() == Qt::Checked) {
++selected_channel_count;
}
}
if (0 == selected_channel_count) {
QMessageBox::information(this, QStringLiteral(u"提示"), QStringLiteral(u"请选择需要保存的测量设备通道配置参数!"));
return;
}
DeviceParamsSaveToSysDlg params_save_to_sys_dlg;
if (QDialog::Accepted == params_save_to_sys_dlg.exec()) {
const QString& device_params_dir_path = QDir(qApp->applicationDirPath()).filePath("configure/DeviceParams");
const QString params_cfg_name = params_save_to_sys_dlg.GetCfgName();
const QString params_cfg_description = params_save_to_sys_dlg.GetCfgDescription();
const QString params_cfg_filename = QDir(device_params_dir_path).filePath(params_cfg_name) + ".mscfg";
if (QFile::exists(params_cfg_filename)) {
QMessageBox::warning(this, QStringLiteral(u"警告"), QStringLiteral(u"设备测量参数配置\"%1\"已存在!").arg(params_cfg_name));
} else {
if (this->SaveSelectedChannelConfig(params_cfg_filename, params_cfg_name, params_cfg_description)) {
this->_cfg_name = params_cfg_name;
this->_cfg_description = params_cfg_description;
QMessageBox::information(this, QStringLiteral(u"提示"), QStringLiteral(u"保存设备测量参数配置\"%1\"完成").arg(params_cfg_name));
}
}
}
}
bool DeviceParamsTableForm::SaveSelectedChannelConfig(const QString &save_filename, const QString& cfg_name, const QString& description)
{
QVariantList device_channel_params_list;
for (int row = 0; row < 32; ++row) {
@ -338,44 +491,82 @@ void DeviceParamsTableForm::onSaveSelectedChannelConfig()
int board_id = channel_info["board_id"].toInt();
int channel_id = channel_info["channel_id"].toInt();
int addr_count = ui->params_cfg_table->item(row, 1)->text().toInt();
int device_gain = ui->params_cfg_table->item(row, 2)->text().toInt();
int device_gain_index = ui->params_cfg_table->item(row, 2)->data(Qt::UserRole).toInt();
uint soft_gain = ui->params_cfg_table->item(row, 3)->text().toUInt();
int time_const = ui->params_cfg_table->item(row, 4)->text().toInt();
int dc_offset = ui->params_cfg_table->item(row, 5)->text().toInt();
int rise_time = ui->params_cfg_table->item(row, 6)->text().toInt();
int flat_time = ui->params_cfg_table->item(row, 7)->text().toInt();
int max_energy = ui->params_cfg_table->item(row, 8)->text().toInt();
auto transfer_mode_value = [](const QString& transfer_mode_text) {
int transfer_mode = 3;
for (QMap<int, QString>::iterator it = s_transfer_mode_list.begin(); it != s_transfer_mode_list.end(); ++it) {
if (it.value() == transfer_mode_text) {
transfer_mode = it.key();
break;
}
}
return transfer_mode;
};
int transfer_mode = transfer_mode_value(ui->params_cfg_table->item(row, 2)->text());
int device_gain = ui->params_cfg_table->item(row, 3)->text().toInt();
int device_gain_index = s_device_gain_list.indexOf(ui->params_cfg_table->item(row, 3)->text()) + 1;
uint soft_gain = ui->params_cfg_table->item(row, 4)->text().toUInt();
double time_const = ui->params_cfg_table->item(row, 5)->text().toDouble();
int dc_offset = ui->params_cfg_table->item(row, 6)->text().toInt();
int form_time = ui->params_cfg_table->item(row, 7)->text().toInt();
double fast_channel_triger_value = ui->params_cfg_table->item(row, 8)->text().toDouble();
auto is_enable = [](const QString& text) {
bool enable = false;
if (QStringLiteral(u"启用") == text) {
enable = true;
} else if (QStringLiteral(u"禁用") == text) {
enable = false;
}
return enable;
};
bool CRDiv_mode = is_enable(ui->params_cfg_table->item(row, 9)->text());
bool input_signal_postive = is_enable(ui->params_cfg_table->item(row, 10)->text());
QVariantMap device_channel_params;
device_channel_params["BoardId"] = board_id;
device_channel_params["ChannelId"] = channel_id;
device_channel_params["AddrCount"] = addr_count;
device_channel_params["TransferMode"] = transfer_mode;
device_channel_params["DeviceGain"] = device_gain;
device_channel_params["DeviceGainSelectIndex"] = device_gain_index;
device_channel_params["SoftGain"] = soft_gain;
device_channel_params["TimeConst"] = time_const;
device_channel_params["DcOffset"] = dc_offset;
device_channel_params["RiseTime"] = rise_time;
device_channel_params["FlatTime"] = flat_time;
device_channel_params["MaxEnergy"] = max_energy;
device_channel_params["FormTime"] = form_time;
device_channel_params["FastChannelTrigerValue"] = fast_channel_triger_value;
device_channel_params["CRDivMode"] = CRDiv_mode;
device_channel_params["InputSignalPostive"] = input_signal_postive;
device_channel_params_list.append(device_channel_params);
}
}
if (device_channel_params_list.isEmpty()) {
QMessageBox::information(this, QStringLiteral(u"提示"), QStringLiteral(u"请选择需要保存的测量设备通道配置参数!"));
return;
}
// if (device_channel_params_list.isEmpty()) {
// QMessageBox::information(this, QStringLiteral(u"提示"), QStringLiteral(u"请选择需要保存的测量设备通道配置参数!"));
// return false;
// }
QVariantMap device_config_info;
if (!cfg_name.isEmpty()) {
QVariantMap cfg_info;
cfg_info["Name"] = cfg_name;
cfg_info["Description"] = description;
device_config_info["ParamsConfigureInfo"] = cfg_info;
}
device_config_info["ChannelConfig"] = device_channel_params_list;
QJsonDocument json_doc = QJsonDocument::fromVariant(device_config_info);
QFile json_file(this->_config_filename);
QFile json_file(save_filename);
if (!json_file.open(QIODevice::WriteOnly | QIODevice::Text)) {
return;
return false;
}
json_file.write(json_doc.toJson());
json_file.close();
LOG_INFO(QStringLiteral(u"测量设备参数配置保存完成."));
emit deviceConfigParamsSaved(this->_config_filename);
LOG_INFO(QStringLiteral(u"测量设备参数配置保存完成: %1.").arg(save_filename));
return true;
}
void DeviceParamsTableForm::ClearParamsTable()
{
for (int row = 0; row < ui->params_cfg_table->rowCount(); ++row) {
for (int col = 1; col < ui->params_cfg_table->columnCount(); ++col) {
ui->params_cfg_table->item(row, col)->setText(QString());
}
}
}

View File

@ -15,11 +15,8 @@ public:
explicit DeviceParamsItemDelegate(QObject *parent = nullptr);
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
void setEditorData(QWidget *editor, const QModelIndex &index) const override;
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
protected:
@ -36,12 +33,20 @@ public:
void SetConfigFilename(const QString& filename);
void SetButtonEnable(bool enable = true);
const QString& GetConfigName() const;
const QString& GetConfigDescription() const;
void ClearParamsTable();
bool SaveSelectedChannelConfig(const QString& save_filename, const QString &cfg_name = QString(), const QString &description = QString());
private slots:
void onAllSelectBtnClicked();
void onReserveSelectBtnClicked();
void onCfgChannelSelectBtnClicked();
void onCurrentChannelToOther();
void onSaveSelectedChannelConfig();
void onSaveSelectedChannelConfigToSys();
signals:
void deviceConfigParamsSaved(const QString& filename);
@ -49,6 +54,8 @@ signals:
private:
Ui::DeviceParamsTableForm *ui;
QString _config_filename;
QString _cfg_name;
QString _cfg_description;
};
#endif // DEVICEPARAMSTABLEFORM_H

View File

@ -42,7 +42,7 @@
<item>
<widget class="QPushButton" name="btn_update_to_other">
<property name="text">
<string>应用当前通道配置到其他通道</string>
<string>应用当前通道配置到选择通道</string>
</property>
</widget>
</item>
@ -68,6 +68,13 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_save_to_sys">
<property name="text">
<string>保存到系统</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
@ -113,16 +120,6 @@
<string>直流偏移</string>
</property>
</column>
<column>
<property name="text">
<string>上升时间</string>
</property>
</column>
<column>
<property name="text">
<string>平顶时间</string>
</property>
</column>
<column>
<property name="text">
<string>成形时间</string>
@ -138,16 +135,6 @@
<string>CR微分模式</string>
</property>
</column>
<column>
<property name="text">
<string>新建列</string>
</property>
</column>
<column>
<property name="text">
<string>新建列</string>
</property>
</column>
<column>
<property name="text">
<string>输入信号正负极性选择</string>

View File

@ -7,6 +7,17 @@
#include "QsLogManage.h"
#include <QThreadPool>
void InitAppRunEnv() {
// 在应用程序可执行文件所在目录检查并创建Projects目录
QString projects_dir_path = QDir(qApp->applicationDirPath()).filePath("Projects");
QDir projects_dir(projects_dir_path);
projects_dir.mkpath(projects_dir_path);
QString device_params_dir_path = QDir(qApp->applicationDirPath()).filePath("configure/DeviceParams");
QDir device_params_dir(device_params_dir_path);
device_params_dir.mkpath(device_params_dir_path);
}
int main(int argc, char *argv[])
{
qputenv("QT_WIN_DEBUG_CONSOLE", "attach");
@ -53,12 +64,7 @@ int main(int argc, char *argv[])
app.setWindowIcon(QIcon(":/logo/256.png"));
app.setQuitOnLastWindowClosed(true);
// 在应用程序可执行文件所在目录检查并创建Projects目录
QString projects_dir_path = QDir(app.applicationDirPath()).filePath("Projects");
QDir projects_dir(projects_dir_path);
if (!projects_dir.exists()) {
projects_dir.mkpath(projects_dir_path);
}
InitAppRunEnv();
MainWindow w;
w.showMaximized();

View File

@ -70,9 +70,6 @@ SOURCES += \
CountRateAnalysisView/CountRateAnalysisView.cpp \
CustomQwtPlot.cpp \
DataProcessWorkPool.cpp \
DeviceParameterConfig/DeviceConfigView.cpp \
DeviceParameterConfig/DeviceParameterConfig.cpp \
DeviceParameterConfig/DeviceParameterConfigList.cpp \
EnergyCountPeakFitView/EnergyCountPeakFitView.cpp \
EnergyCountPeakFitView/PeakFitParamsDialog.cpp \
EnergyCountPeakFitView/PlotRectItem.cpp \
@ -82,6 +79,8 @@ SOURCES += \
MainWindow.cpp \
MeasureAnalysisDataTableView/MeasureAnalysisDataTableView.cpp \
MeasureAnalysisHistoryForm/MeasureAnalysisHistoryForm.cpp \
MeasureDeviceParamsConfigView/DeviceParamsManagerDlg.cpp \
MeasureDeviceParamsConfigView/DeviceParamsSaveToSysDlg.cpp \
MeasureDeviceParamsConfigView/DeviceParamsTableForm.cpp \
MeasureDeviceParamsConfigView/MeasureDeviceParamsConfigView.cpp \
NuclideLib/sqlitemanager.cpp \
@ -90,7 +89,6 @@ SOURCES += \
ParticleCountPlotView/ParticleCountPlotView.cpp \
MeasureAnalysisTreeView.cpp \
MeasureAnalysisView.cpp \
MeasureDeviceParamsCfgForm.cpp \
NewMeasureAnalysisDlg.cpp \
MeasureAnalysisProjectModel.cpp \
ParticleInjectTimeView/ParticleInjectTimeAnalysisView.cpp \
@ -104,7 +102,6 @@ SOURCES += \
ThreeDimensionalConformityAnalysisView/ParticleDataStatistics.cpp \
ThreeDimensionalConformityAnalysisView/ThreeDDisplay.cpp \
EnergyCountPeakFitView/EnergyCountPeakFitView.cpp \
DeviceParameterConfig/DeviceParameterProxy.cpp \
ConformToTheEnergySpectrum/ConformToTheEnergySpectrum.cpp \
NuclideLib/NuclideLib.cpp \
main.cpp
@ -117,9 +114,6 @@ HEADERS += \
CountRateAnalysisView/CountRateAnalysisView.h \
CustomQwtPlot.h \
DataProcessWorkPool.h \
DeviceParameterConfig/DeviceConfigView.h \
DeviceParameterConfig/DeviceParameterConfig.h \
DeviceParameterConfig/DeviceParameterConfigList.h \
EnergyCountPeakFitView/EnergyCountPeakFitView.h \
EnergyCountPeakFitView/PeakFitParamsDialog.h \
EnergyCountPeakFitView/PlotRectItem.h \
@ -130,6 +124,8 @@ HEADERS += \
MainWindow.h \
MeasureAnalysisDataTableView/MeasureAnalysisDataTableView.h \
MeasureAnalysisHistoryForm/MeasureAnalysisHistoryForm.h \
MeasureDeviceParamsConfigView/DeviceParamsManagerDlg.h \
MeasureDeviceParamsConfigView/DeviceParamsSaveToSysDlg.h \
MeasureDeviceParamsConfigView/DeviceParamsTableForm.h \
MeasureDeviceParamsConfigView/MeasureDeviceParamsConfigView.h \
NuclideLib/sqlitemanager.h \
@ -138,7 +134,6 @@ HEADERS += \
ParticleCountPlotView/ParticleCountPlotView.h \
MeasureAnalysisTreeView.h \
MeasureAnalysisView.h \
MeasureDeviceParamsCfgForm.h \
NewMeasureAnalysisDlg.h \
MeasureAnalysisProjectModel.h \
ParticleInjectTimeView/ParticleInjectTimeAnalysisView.h \
@ -153,7 +148,6 @@ HEADERS += \
ThreeDimensionalConformityAnalysisView/ParticleDataStatistics.h \
ThreeDimensionalConformityAnalysisView/ThreeDDisplay.h \
EnergyCountPeakFitView/EnergyCountPeakFitView.h \
DeviceParameterConfig/DeviceParameterProxy.h \
ConformToTheEnergySpectrum/ConformToTheEnergySpectrum.h \
NuclideLib/NuclideLib.h
@ -167,9 +161,10 @@ FORMS += \
EnergyScaleForm.ui \
MainWindow.ui \
MeasureAnalysisHistoryForm/MeasureAnalysisHistoryForm.ui \
MeasureDeviceParamsConfigView/DeviceParamsManagerDlg.ui \
MeasureDeviceParamsConfigView/DeviceParamsSaveToSysDlg.ui \
MeasureDeviceParamsConfigView/DeviceParamsTableForm.ui \
ParticleCountPlotView/BatchEnergyScaleDialog.ui \
MeasureDeviceParamsCfgForm.ui \
NewMeasureAnalysisDlg.ui \
ThreeDimensionalConformityAnalysisView/DetectorStatusSummary.ui \
ThreeDimensionalConformityAnalysisView/ParticleDataStatistics.ui \

View File

@ -48,7 +48,7 @@ QHeaderView::section {
font-weight: normal;
}
/*
QScrollBar {
background-color: #f6f5ec;
padding: 0px;
@ -90,5 +90,5 @@ QScrollBar::add-page {
QScrollBar::sub-page {
background: rgba(0, 0, 0, 0);
}
*/