修改以下 峰拟合框线条粗细变化问题,峰拟合结果对话框中的表头适应内容;峰拟合当前选择的峰拟合结果的峰信息着重显示黑色、未选中的峰信息显示暗淡灰色;删除锋拟合结果后剩下的峰拟合结果项会自动勾选;峰拟合图表中的本地曲线的颜色使用暗黄色,核素库删除核素,其相关的射线记录未删除;核素库管理对话框名称修改为“核素库";核素库添加成功时,先将数据添加到数据库中,在界面显示,再弹出添加成功对话框,核素库半衰期的参数输入应支持”年、月、日、时、分、秒“的单位;修改符合二维符合能谱只加载两个粒子的数据

This commit is contained in:
anxinglong 2026-05-18 18:34:52 +08:00
parent 20ea8ad131
commit 0f0a46c5f7
11 changed files with 283 additions and 91 deletions

Binary file not shown.

View File

@ -23,7 +23,10 @@
#include <QwtText> #include <QwtText>
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include <QFileInfo>
#include <qwt_matrix_raster_data.h> #include <qwt_matrix_raster_data.h>
#include "csv.h"
#include <GlobalDefine.h>
class HeatMapColorMap : public QwtLinearColorMap { class HeatMapColorMap : public QwtLinearColorMap {
public: public:
@ -65,12 +68,18 @@ void TwoDSpectralCompliance::SetAnalyzeDataFilename(const QMap<QString, QVariant
{ {
if (data_files_set.isEmpty()) if (data_files_set.isEmpty())
return; return;
QString csvFile = data_files_set.first().toString(); QStringList _data_filenames;
if (csvFile.isEmpty())
return; for (const QVariant& file_value : data_files_set) {
QString filename = file_value.toString();
if (!filename.isEmpty() && QFileInfo(filename).exists()) {
_data_filenames.append(filename);
}
}
_busy_indicator->Start(); _busy_indicator->Start();
auto functionToRun = [this, csvFile]() { auto functionToRun = [this, _data_filenames]() {
readCsv(csvFile); readCsv(_data_filenames);
generateSurfaceData(); generateSurfaceData();
QMetaObject::invokeMethod(this, [this]() { QMetaObject::invokeMethod(this, [this]() {
updateSpectrogram(); updateSpectrogram();
@ -115,37 +124,35 @@ void TwoDSpectralCompliance::setupPlot()
_spectrogram->attach(_plot); _spectrogram->attach(_plot);
} }
void TwoDSpectralCompliance::readCsv(const QString& filename) void TwoDSpectralCompliance::readCsv(const QStringList& filename)
{ {
m_rawData.clear(); if (filename.isEmpty()) {
QFile file(filename); QMetaObject::invokeMethod(this, [this]() {
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { _busy_indicator->Stop();
qWarning() << QStringLiteral(u"无法打开文件:") << filename; }, Qt::QueuedConnection);
return; return;
} }
for (const QString& filename : filename) {
QTextStream stream(&file); io::CSVReader<5> in(QStrToSysPath(filename));
QString header = stream.readLine(); in.read_header(io::ignore_extra_column,
Q_UNUSED(header); QString(QStringLiteral(u"事件ID")).toStdString(),
QString(QStringLiteral(u"板卡号")).toStdString(),
while (!stream.atEnd()) { QString(QStringLiteral(u"通道号")).toStdString(),
QString line = stream.readLine(); QString(QStringLiteral(u"能量(KeV)")).toStdString(),
if (line.isEmpty()) QString(QStringLiteral(u"时间计数")).toStdString());
continue; int eventId,board, channel;
double energy;
QStringList fields = line.split(','); unsigned long long time_count;
if (fields.size() < 5) while (in.read_row(eventId,board, channel, energy, time_count)) {
continue; EventData sd;
sd.eventId = eventId;
EventData data; sd.board = board;
data.eventId = fields[0].toInt(); sd.channel = channel;
data.board = fields[1].toInt(); sd.energy = energy;
data.channel = fields[2].toInt(); sd.timeCounter = time_count;
data.energy = fields[3].toDouble(); m_rawData.push_back(sd);
data.timeCounter = fields[4].toULongLong(); }
m_rawData.append(data);
} }
file.close();
} }
void TwoDSpectralCompliance::generateSurfaceData() void TwoDSpectralCompliance::generateSurfaceData()

View File

@ -39,7 +39,7 @@ protected:
private: private:
void setupPlot(); void setupPlot();
void readCsv(const QString& filename); void readCsv(const QStringList& filename);
void generateSurfaceData(); void generateSurfaceData();
void updateSpectrogram(); void updateSpectrogram();

View File

@ -25,7 +25,6 @@
#include <QFileInfo> #include <QFileInfo>
#include "PlotRectItem.h" #include "PlotRectItem.h"
#include <QInputDialog> #include <QInputDialog>
#include <QDebug>
#include <QPainter> #include <QPainter>
#include <QMessageBox> #include <QMessageBox>
#include <QListWidget> #include <QListWidget>
@ -223,7 +222,7 @@ void EnergyCountPeakFitView::setupPlot()
dummyFit->attach(_plot); dummyFit->attach(_plot);
QwtPlotCurve *dummyBg = new QwtPlotCurve(QStringLiteral(u"本底数据")); QwtPlotCurve *dummyBg = new QwtPlotCurve(QStringLiteral(u"本底数据"));
dummyBg->setPen(QPen(Qt::yellow, 2)); dummyBg->setPen(QPen(QColor("#C9A84C"), 2));
dummyBg->setSamples(QVector<double>(), QVector<double>()); dummyBg->setSamples(QVector<double>(), QVector<double>());
dummyBg->setVisible(false); dummyBg->setVisible(false);
dummyBg->attach(_plot); dummyBg->attach(_plot);
@ -551,7 +550,7 @@ void EnergyCountPeakFitView::fadeSelectionRectBorders()
{ {
for (PlotRectItem* item : _selectionRectItems) { for (PlotRectItem* item : _selectionRectItems) {
if (item) { if (item) {
QPen fadedPen(Qt::red, 1, Qt::DashLine); QPen fadedPen(Qt::red, 2, Qt::DashLine);
item->setPen(fadedPen); item->setPen(fadedPen);
} }
} }
@ -593,12 +592,12 @@ QList<PeakFitResult> EnergyCountPeakFitView::performPeakFitting(const QVector<do
FitParams userParams = paramDlg.getParams(); FitParams userParams = paramDlg.getParams();
AdaptiveSimpsonIntegrate::FitFunction fitFunc; AdaptiveSimpsonIntegrate::FitFunction fitFunc;
fitFunc.A = userParams.A ;//p_fit(0); fitFunc.A = userParams.A ;
fitFunc.delt= userParams.delt;//p_fit(1); fitFunc.delt= userParams.delt;
fitFunc.H = userParams.H ;//p_fit(2); fitFunc.H = userParams.H ;
fitFunc.W = userParams.W ;//p_fit(3); fitFunc.W = userParams.W ;
fitFunc.C = userParams.C ;//p_fit(4); fitFunc.C = userParams.C ;
fitFunc.P = userParams.P ;//p_fit(5); fitFunc.P = userParams.P ;
double lower = fitFunc.P - 3.0 * fitFunc.delt; double lower = fitFunc.P - 3.0 * fitFunc.delt;
double upper = fitFunc.P + 3.0 * fitFunc.delt; double upper = fitFunc.P + 3.0 * fitFunc.delt;
double area = AdaptiveSimpsonIntegrate::integrate(fitFunc, lower, upper); double area = AdaptiveSimpsonIntegrate::integrate(fitFunc, lower, upper);
@ -670,7 +669,7 @@ QList<QwtPlotCurve *> EnergyCountPeakFitView::createFitCurve(const PeakFitResult
curveList.append(curve); curveList.append(curve);
QwtPlotCurve* curveTw = new QwtPlotCurve(QStringLiteral(u"本底数据")); QwtPlotCurve* curveTw = new QwtPlotCurve(QStringLiteral(u"本底数据"));
curveTw->setPen(QPen(Qt::yellow, 2)); curveTw->setPen(QPen(QColor("#C9A84C"), 2));
curveTw->setSamples(xs, ysTw); curveTw->setSamples(xs, ysTw);
curveTw->setItemAttribute(QwtPlotItem::Legend, false); curveTw->setItemAttribute(QwtPlotItem::Legend, false);
curveTw->attach(_plot); curveTw->attach(_plot);
@ -679,6 +678,64 @@ QList<QwtPlotCurve *> EnergyCountPeakFitView::createFitCurve(const PeakFitResult
return curveList; return curveList;
} }
void EnergyCountPeakFitView::updateHistoryDialogWithSelection(const QList<DisplayedCurveRef> &selectedRefs)
{
if (!_historyDlg) return;
QTableView* tableView = _historyDlg->findChild<QTableView*>("historyTableView");
QStandardItemModel* model = qobject_cast<QStandardItemModel*>(tableView ? tableView->model() : nullptr);
if (!model) return;
// 将选中的引用转换为集合,方便快速查找
QSet<QPair<int, int>> selectedSet;
for (const auto& ref : selectedRefs) {
selectedSet.insert(qMakePair(ref.historyIndex, ref.curveIndex));
}
// 重新构建表格
model->clear();
QStringList headers;
headers << "序号" << "振幅(A)" << "高斯宽度(delt)" << "Sigmoid幅度(H)" << "Sigmoid宽度(W)" << "基线(C)";
model->setHorizontalHeaderLabels(headers);
QVector<QPair<int, int>> newRowMap;
model->blockSignals(true);
int rowNumber = 1;
for (int historyIdx = 0; historyIdx < _fitHistoryList.size(); ++historyIdx) {
const auto& historyItem = _fitHistoryList[historyIdx];
for (int curveIdx = 0; curveIdx < historyItem.curveList.size(); ++curveIdx) {
const auto& curve = historyItem.curveList[curveIdx];
QList<QStandardItem*> rowItems;
QStandardItem* checkItem = new QStandardItem(QString::number(rowNumber++));
checkItem->setCheckable(true);
checkItem->setEditable(false);
checkItem->setCheckState(selectedSet.contains(qMakePair(historyIdx, curveIdx))
? Qt::Checked : Qt::Unchecked);
rowItems.append(checkItem);
rowItems.append(new QStandardItem(QString::number(curve.amplitude, 'f', 4)));
rowItems.append(new QStandardItem(QString::number(curve.sigma, 'f', 4)));
rowItems.append(new QStandardItem(QString::number(curve.sigmoidH, 'f', 4)));
rowItems.append(new QStandardItem(QString::number(curve.sigmoidW, 'f', 4)));
rowItems.append(new QStandardItem(QString::number(curve.baseline, 'f', 4)));
model->appendRow(rowItems);
newRowMap.append(qMakePair(historyIdx, curveIdx));
}
}
model->blockSignals(false);
_historyDlg->setProperty("rowToDataIndices", QVariant::fromValue(newRowMap));
tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
tableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
tableView->horizontalHeader()->resizeSection(0, 70);
tableView->horizontalHeader()->setStretchLastSection(true);
tableView->viewport()->update();
LOG_DEBUG(QStringLiteral(u"历史对话框已更新"));
}
void EnergyCountPeakFitView::clearFitCurves() void EnergyCountPeakFitView::clearFitCurves()
{ {
@ -776,17 +833,18 @@ void EnergyCountPeakFitView::onActionShowFitHistory()
break; break;
} }
} }
if (!hasCurveData) { //空表时直接打开
QMessageBox* msgBox = new QMessageBox(this); // if (!hasCurveData) {
msgBox->setWindowTitle(QStringLiteral(u"峰拟合结果")); // QMessageBox* msgBox = new QMessageBox(this);
msgBox->setText(QStringLiteral(u"暂无历史拟合数据,请先进行拟合并保存。")); // msgBox->setWindowTitle(QStringLiteral(u"峰拟合结果"));
msgBox->setStandardButtons(QMessageBox::Ok); // msgBox->setText(QStringLiteral(u"暂无历史拟合数据,请先进行拟合并保存。"));
msgBox->setModal(false); // msgBox->setStandardButtons(QMessageBox::Ok);
msgBox->setAttribute(Qt::WA_DeleteOnClose); // msgBox->setModal(false);
msgBox->setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint); // msgBox->setAttribute(Qt::WA_DeleteOnClose);
msgBox->show(); // msgBox->setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint);
return; // msgBox->show();
} // return;
// }
if (_historyDlg) { if (_historyDlg) {
_historyDlg->raise(); _historyDlg->raise();
@ -852,9 +910,15 @@ void EnergyCountPeakFitView::onActionShowFitHistory()
tableView->setSelectionBehavior(QAbstractItemView::SelectRows); tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
tableView->setSelectionMode(QAbstractItemView::SingleSelection); tableView->setSelectionMode(QAbstractItemView::SingleSelection);
tableView->setEditTriggers(QAbstractItemView::NoEditTriggers); tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
tableView->horizontalHeader()->setStretchLastSection(true);
tableView->verticalHeader()->setVisible(false); tableView->verticalHeader()->setVisible(false);
// 关键:先设置所有列为拉伸模式
tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
// 再单独将序号列(第0列)设置为固定宽度
tableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
tableView->horizontalHeader()->resizeSection(0, 70);
// 最后设置最后一列拉伸
tableView->horizontalHeader()->setStretchLastSection(true);
layout->addWidget(tableView); layout->addWidget(tableView);
QPushButton* btnDelete = new QPushButton(QStringLiteral(u"删除选中记录"), _historyDlg); QPushButton* btnDelete = new QPushButton(QStringLiteral(u"删除选中记录"), _historyDlg);
@ -1015,8 +1079,10 @@ void EnergyCountPeakFitView::onActionShowFitHistory()
} }
saveHistoryToFile(); saveHistoryToFile();
if (_historyDlg) {
emit newFitResultAdded(); updateHistoryDialogWithSelection(remainingRefs);
}
// emit newFitResultAdded();
} }
}); });
confirmBox->show(); confirmBox->show();
@ -1028,6 +1094,71 @@ void EnergyCountPeakFitView::onActionShowFitHistory()
void EnergyCountPeakFitView::onActionDeleteHoveredRect() void EnergyCountPeakFitView::onActionDeleteHoveredRect()
{ {
// if (!_hoveredRectItem) {
// QMessageBox::information(this, QStringLiteral(u"提示"),
// QStringLiteral(u"请先将鼠标移动到要删除的框选区域上(区域边框会变为实线),然后再点击此菜单。"));
// return;
// }
// QString rectType = _hoveredRectItem->selectionType();
// int historyIndex = _hoveredRectItem->selectionIndex();
// int curveStartIdx = historyIndex * 2;
// if (curveStartIdx + 1 < _fitCurves.size()) {
// _fitCurves[curveStartIdx + 1]->detach();
// delete _fitCurves[curveStartIdx + 1];
// _fitCurves.removeAt(curveStartIdx + 1);
// _fitCurves[curveStartIdx]->detach();
// delete _fitCurves[curveStartIdx];
// _fitCurves.removeAt(curveStartIdx);
// }
// _hoveredRectItem->detach();
// delete _hoveredRectItem;
// for (auto it = _selectionRectItems.begin(); it != _selectionRectItems.end();) {
// if (*it && (*it)->selectionIndex() == historyIndex) {
// it = _selectionRectItems.erase(it);
// } else {
// ++it;
// }
// }
// _hoveredRectItem = nullptr;
// if (historyIndex >= 0 && historyIndex < _fitHistoryList.size()) {
// _fitHistoryList.removeAt(historyIndex);
// saveHistoryToFile();
// }
// for (auto& ref : _displayedHistoryCurves) {
// if (ref.historyIndex > historyIndex) {
// ref.historyIndex--;
// ref.rectIndex = ref.historyIndex;
// ref.curveStartIndex = ref.rectIndex * 2;
// }
// }
// for (auto it = _displayedHistoryCurves.begin(); it != _displayedHistoryCurves.end();) {
// if (it->historyIndex == historyIndex) {
// it = _displayedHistoryCurves.erase(it);
// } else {
// ++it;
// }
// }
// for (PlotRectItem* item : _selectionRectItems) {
// if (item && item->selectionIndex() > historyIndex) {
// item->setSelectionIndex(item->selectionIndex() - 1);
// }
// }
// for (auto& record : _currentFitRecords) {
// if (record.historyIndex > historyIndex) {
// record.historyIndex--;
// }
// }
// _plot->replot();
// emit newFitResultAdded();
if (!_hoveredRectItem) { if (!_hoveredRectItem) {
QMessageBox::information(this, QStringLiteral(u"提示"), QMessageBox::information(this, QStringLiteral(u"提示"),
QStringLiteral(u"请先将鼠标移动到要删除的框选区域上(区域边框会变为实线),然后再点击此菜单。")); QStringLiteral(u"请先将鼠标移动到要删除的框选区域上(区域边框会变为实线),然后再点击此菜单。"));
@ -1035,7 +1166,6 @@ void EnergyCountPeakFitView::onActionDeleteHoveredRect()
} }
QString rectType = _hoveredRectItem->selectionType(); QString rectType = _hoveredRectItem->selectionType();
int historyIndex = _hoveredRectItem->selectionIndex(); int historyIndex = _hoveredRectItem->selectionIndex();
int curveStartIdx = historyIndex * 2; int curveStartIdx = historyIndex * 2;
if (curveStartIdx + 1 < _fitCurves.size()) { if (curveStartIdx + 1 < _fitCurves.size()) {
_fitCurves[curveStartIdx + 1]->detach(); _fitCurves[curveStartIdx + 1]->detach();
@ -1045,7 +1175,6 @@ void EnergyCountPeakFitView::onActionDeleteHoveredRect()
delete _fitCurves[curveStartIdx]; delete _fitCurves[curveStartIdx];
_fitCurves.removeAt(curveStartIdx); _fitCurves.removeAt(curveStartIdx);
} }
_hoveredRectItem->detach(); _hoveredRectItem->detach();
delete _hoveredRectItem; delete _hoveredRectItem;
for (auto it = _selectionRectItems.begin(); it != _selectionRectItems.end();) { for (auto it = _selectionRectItems.begin(); it != _selectionRectItems.end();) {
@ -1056,41 +1185,52 @@ void EnergyCountPeakFitView::onActionDeleteHoveredRect()
} }
} }
_hoveredRectItem = nullptr; _hoveredRectItem = nullptr;
if (historyIndex >= 0 && historyIndex < _fitHistoryList.size()) { if (historyIndex >= 0 && historyIndex < _fitHistoryList.size()) {
_fitHistoryList.removeAt(historyIndex); _fitHistoryList.removeAt(historyIndex);
saveHistoryToFile(); saveHistoryToFile();
} }
QList<DisplayedCurveRef> remainingRefs;
for (auto& ref : _displayedHistoryCurves) { for (auto& ref : _displayedHistoryCurves) {
if (ref.historyIndex == historyIndex) {
continue; // 跳过要删除的记录
}
if (ref.historyIndex > historyIndex) { if (ref.historyIndex > historyIndex) {
ref.historyIndex--; ref.historyIndex--;
ref.rectIndex = ref.historyIndex; ref.rectIndex = ref.historyIndex;
ref.curveStartIndex = ref.rectIndex * 2; ref.curveStartIndex = ref.rectIndex * 2;
} }
remainingRefs.append(ref);
} }
for (auto it = _displayedHistoryCurves.begin(); it != _displayedHistoryCurves.end();) {
if (it->historyIndex == historyIndex) { _displayedHistoryCurves = remainingRefs;
it = _displayedHistoryCurves.erase(it);
} else {
++it;
}
}
for (PlotRectItem* item : _selectionRectItems) { for (PlotRectItem* item : _selectionRectItems) {
if (item && item->selectionIndex() > historyIndex) { if (item && item->selectionIndex() > historyIndex) {
item->setSelectionIndex(item->selectionIndex() - 1); item->setSelectionIndex(item->selectionIndex() - 1);
} }
} }
for (auto& record : _currentFitRecords) { for (auto& record : _currentFitRecords) {
if (record.historyIndex > historyIndex) { if (record.historyIndex > historyIndex) {
record.historyIndex--; record.historyIndex--;
} }
} }
_plot->replot(); clearFitCurves();
emit newFitResultAdded(); clearAllSelectionRects();
if (!remainingRefs.isEmpty()) {
QList<FitCurveData> remainingCurves;
for (const auto& ref : remainingRefs) {
remainingCurves.append(_fitHistoryList[ref.historyIndex].curveList[ref.curveIndex]);
}
displaySelectedCurves(remainingCurves, remainingRefs);
} else {
_plot->replot();
}
if (_historyDlg) {
updateHistoryDialogWithSelection(remainingRefs);
}
} }
void EnergyCountPeakFitView::onActionRefitCurrentRect() void EnergyCountPeakFitView::onActionRefitCurrentRect()
@ -1300,7 +1440,7 @@ void EnergyCountPeakFitView::displaySelectedCurves(const QList<FitCurveData> &cu
for (int j = 0; j < yTw.size(); ++j) ysTw.append(yTw(j)); for (int j = 0; j < yTw.size(); ++j) ysTw.append(yTw(j));
QwtPlotCurve* bgCurve = new QwtPlotCurve(QStringLiteral(u"历史本底数据")); QwtPlotCurve* bgCurve = new QwtPlotCurve(QStringLiteral(u"历史本底数据"));
bgCurve->setPen(QPen(Qt::yellow, 2, Qt::DashLine)); bgCurve->setPen(QPen(QColor("#C9A84C"), 2, Qt::DashLine));
bgCurve->setSamples(xs, ysTw); bgCurve->setSamples(xs, ysTw);
bgCurve->setItemAttribute(QwtPlotItem::Legend, false); bgCurve->setItemAttribute(QwtPlotItem::Legend, false);
bgCurve->attach(_plot); bgCurve->attach(_plot);
@ -1423,7 +1563,10 @@ void EnergyCountPeakFitView::onNewFitResultAdded()
} }
} }
displaySelectedCurves(selectedCurves, selectedRefs); displaySelectedCurves(selectedCurves, selectedRefs);
tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
tableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
tableView->horizontalHeader()->resizeSection(0, 70);
tableView->horizontalHeader()->setStretchLastSection(true);
tableView->viewport()->update(); tableView->viewport()->update();
LOG_DEBUG(QStringLiteral(u"历史对话框已同步刷新")); LOG_DEBUG(QStringLiteral(u"历史对话框已同步刷新"));
} }

View File

@ -129,6 +129,8 @@ private:
QList<PeakFitResult> performPeakFitting(const QVector<double>& x, const QVector<double>& y /*, const arma::vec* userP0 = nullptr*/); QList<PeakFitResult> performPeakFitting(const QVector<double>& x, const QVector<double>& y /*, const arma::vec* userP0 = nullptr*/);
// 根据拟合参数生成曲线 // 根据拟合参数生成曲线
QList<QwtPlotCurve*> createFitCurve(const PeakFitResult& result, arma::vec xVec); QList<QwtPlotCurve*> createFitCurve(const PeakFitResult& result, arma::vec xVec);
// 更新历史对话框并保持指定的选中状态
void updateHistoryDialogWithSelection(const QList<DisplayedCurveRef>& selectedRefs);
signals: signals:
void newFitResultAdded(); void newFitResultAdded();

View File

@ -13,6 +13,10 @@ PlotRectItem::PlotRectItem(const QString &title)
m_hoverPen = QPen(Qt::red, 2, Qt::SolidLine); m_hoverPen = QPen(Qt::red, 2, Qt::SolidLine);
m_brush = QBrush(QColor(255, 0, 0, 30)); m_brush = QBrush(QColor(255, 0, 0, 30));
m_normalTextPen = QPen(Qt::gray); // 普通状态黑色文本
m_hoverTextPen = QPen(Qt::black); // 悬停状态高亮黑色文本
m_hoverTextPen.setWidth(1); // 稍微加粗
} }
void PlotRectItem::setRect(const QRectF &rect) { void PlotRectItem::setRect(const QRectF &rect) {
@ -98,6 +102,10 @@ void PlotRectItem::draw(QPainter *painter,
// 绘制半透明背景框(增强可读性) // 绘制半透明背景框(增强可读性)
QFont font = painter->font(); QFont font = painter->font();
font.setPointSize(9); // 稍微小一点 font.setPointSize(9); // 稍微小一点
// 悬停时加粗字体
// if (m_isHovered) {
// font.setBold(true);
// }
painter->setFont(font); painter->setFont(font);
QFontMetrics fm(font); QFontMetrics fm(font);
@ -105,8 +113,8 @@ void PlotRectItem::draw(QPainter *painter,
textRect.moveTopLeft(textPos); textRect.moveTopLeft(textPos);
textRect.adjust(-5, -3, 5, 3); // 增加边距 textRect.adjust(-5, -3, 5, 3); // 增加边距
painter->fillRect(textRect, QColor(255, 255, 255, 220)); // 白底微透 painter->fillRect(textRect, QColor(255, 255, 255, 0)); // 白底微透
painter->setPen(Qt::black); painter->setPen(m_isHovered ? m_hoverTextPen : m_normalTextPen);
painter->drawText(textRect, Qt::AlignLeft, text); painter->drawText(textRect, Qt::AlignLeft, text);
painter->restore(); painter->restore();

View File

@ -38,6 +38,8 @@ private:
QPen m_normalPen; //普通状态画笔(虚线) QPen m_normalPen; //普通状态画笔(虚线)
QPen m_hoverPen; //悬停状态画笔(实线) QPen m_hoverPen; //悬停状态画笔(实线)
QBrush m_brush; QBrush m_brush;
QPen m_normalTextPen; // 普通状态文本画笔
QPen m_hoverTextPen; // 悬停状态高亮文本画笔
bool m_isHovered; //悬停状态标志 bool m_isHovered; //悬停状态标志

View File

@ -71,12 +71,6 @@ bool NuclideEditDialog::validateInput()
} }
bool ok; bool ok;
// 半衰期校验保留原逻辑TEXT类型可存储带单位的字符串
m_leHalfLife->text().toDouble(&ok);
if (!ok) {
QMessageBox::warning(this, "输入错误", "半衰期必须为数字可带单位如12.5d");
return false;
}
m_leHalfLifeUnc->text().toDouble(&ok); m_leHalfLifeUnc->text().toDouble(&ok);
if (!ok) { if (!ok) {
QMessageBox::warning(this, "输入错误", "半衰期不确定度必须为有效数字!"); QMessageBox::warning(this, "输入错误", "半衰期不确定度必须为有效数字!");

View File

@ -16,7 +16,12 @@ void ButtonDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option
{ {
if (index.column() == 7) { if (index.column() == 7) {
QStyleOptionButton button; QStyleOptionButton button;
button.rect = option.rect; const int btnWidth = 180; // 按钮宽度(可根据需要调整)
const int btnHeight = option.rect.height() - 4; // 按钮高度上下各留2px边距
const int x = option.rect.x() + (option.rect.width() - btnWidth) / 2; // 水平居中
const int y = option.rect.y() + 2; // 垂直居中(上下边距)
button.rect = QRect(x, y, btnWidth, btnHeight);
// button.rect = option.rect;
button.text = QStringLiteral(u"核素发射射线信息"); button.text = QStringLiteral(u"核素发射射线信息");
button.state = QStyle::State_Enabled; button.state = QStyle::State_Enabled;
if (option.state & QStyle::State_MouseOver) if (option.state & QStyle::State_MouseOver)
@ -53,7 +58,7 @@ NuclideLibManage::NuclideLibManage(QWidget *parent) :
ui->tableView->setColumnHidden(0, true); ui->tableView->setColumnHidden(0, true);
ui->tableView->setColumnWidth(1, 90); // 序号 ui->tableView->setColumnWidth(1, 90); // 序号
ui->tableView->setColumnWidth(7, 280); // 操作列 ui->tableView->setColumnWidth(7, 180); // 操作列
ui->tableView->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch); ui->tableView->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch);
ui->tableView->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Stretch); ui->tableView->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Stretch);
ui->tableView->horizontalHeader()->setSectionResizeMode(4, QHeaderView::Stretch); ui->tableView->horizontalHeader()->setSectionResizeMode(4, QHeaderView::Stretch);
@ -159,8 +164,8 @@ void NuclideLibManage::on_pushButton_add_clicked()
qint64 newId = SqliteManager::instance().insertRow("nuclideLib", fieldValues); qint64 newId = SqliteManager::instance().insertRow("nuclideLib", fieldValues);
if (newId > 0) { if (newId > 0) {
QMessageBox::information(this, QStringLiteral(u"成功"), QStringLiteral(u"核素添加成功!"));
loadNuclideData(); loadNuclideData();
QMessageBox::information(this, QStringLiteral(u"成功"), QStringLiteral(u"核素添加成功!"));
} else { } else {
QMessageBox::warning(this, QStringLiteral(u"失败"), QStringLiteral(u"添加失败:") + SqliteManager::instance().lastError()); QMessageBox::warning(this, QStringLiteral(u"失败"), QStringLiteral(u"添加失败:") + SqliteManager::instance().lastError());
} }
@ -219,19 +224,50 @@ void NuclideLibManage::on_pushButton_del_clicked()
} }
int row = selected.first().row(); int row = selected.first().row();
QString id = m_model->index(row, 0).data().toString(); QString nuclideId = m_model->index(row, 0).data().toString();
QMessageBox box(QMessageBox::Question, QStringLiteral(u"提示"), QStringLiteral(u"确定删除该核素吗?"), QMessageBox box(QMessageBox::Question, QStringLiteral(u"提示"),
QStringLiteral(u"确定删除该核素及其所有关联的射线信息吗?"),
QMessageBox::Yes | QMessageBox::No, this); QMessageBox::Yes | QMessageBox::No, this);
box.button(QMessageBox::Yes)->setText(QStringLiteral(u"确认")); box.button(QMessageBox::Yes)->setText(QStringLiteral(u"确认"));
box.button(QMessageBox::No)->setText(QStringLiteral(u"取消")); box.button(QMessageBox::No)->setText(QStringLiteral(u"取消"));
if (box.exec() != QMessageBox::Yes) return; if (box.exec() != QMessageBox::Yes) return;
bool ok = SqliteManager::instance().deleteRow("nuclideLib", "ID = ?", {id}); SqliteManager& dbMgr = SqliteManager::instance();
if (ok) { // 开始事务
loadNuclideData(); if (!dbMgr.beginTransaction()) {
QMessageBox::warning(this, QStringLiteral(u"错误"),
QStringLiteral(u"开启事务失败:") + dbMgr.lastError());
return;
}
// 步骤1删除该核素关联的所有射线信息
int rayDelCount = dbMgr.deleteRow("nuclideRayInfo", "NUCLIDE_ID = ?", {nuclideId.toInt()});
if (rayDelCount == -1) { // 删除射线失败
dbMgr.rollbackTransaction(); // 回滚事务
QMessageBox::warning(this, QStringLiteral(u"错误"),
QStringLiteral(u"删除关联射线信息失败:") + dbMgr.lastError());
return;
}
// 步骤2删除核素本身
int nuclideDelCount = dbMgr.deleteRow("nuclideLib", "ID = ?", {nuclideId});
if (nuclideDelCount == -1) { // 删除核素失败
dbMgr.rollbackTransaction(); // 回滚事务
QMessageBox::warning(this, QStringLiteral(u"错误"),
QStringLiteral(u"删除核素失败:") + dbMgr.lastError());
return;
}
// 提交事务(所有操作成功)
if (dbMgr.commitTransaction()) {
QMessageBox::information(this, QStringLiteral(u"成功"),
QStringLiteral(u"核素及关联的%1条射线信息已删除").arg(rayDelCount));
loadNuclideData(); // 刷新核素列表
} else { } else {
QMessageBox::warning(this, QStringLiteral(u"错误"), QStringLiteral(u"删除失败:") + SqliteManager::instance().lastError()); dbMgr.rollbackTransaction();
QMessageBox::warning(this, QStringLiteral(u"错误"),
QStringLiteral(u"提交事务失败:") + dbMgr.lastError());
} }
} }

View File

@ -11,7 +11,7 @@
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>NuclideLibManage</string> <string>核素库</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>

View File

@ -182,8 +182,8 @@ void NuclideRayListDialog::onAddRayClicked()
qint64 newId = SqliteManager::instance().insertRow("nuclideRayInfo", fieldValues); qint64 newId = SqliteManager::instance().insertRow("nuclideRayInfo", fieldValues);
if (newId > 0) { if (newId > 0) {
QMessageBox::information(this, QStringLiteral(u"成功"), QStringLiteral(u"射线信息添加成功!"));
loadRayData(); // 刷新列表 loadRayData(); // 刷新列表
QMessageBox::information(this, QStringLiteral(u"成功"), QStringLiteral(u"射线信息添加成功!"));
} else { } else {
QMessageBox::warning(this, QStringLiteral(u"失败"), QStringLiteral(u"添加失败:") + SqliteManager::instance().lastError()); QMessageBox::warning(this, QStringLiteral(u"失败"), QStringLiteral(u"添加失败:") + SqliteManager::instance().lastError());
} }