diff --git a/src/CoincidenceEventTimeView/CoincidenceEventTimeView.cpp b/src/CoincidenceEventTimeView/CoincidenceEventTimeView.cpp new file mode 100644 index 0000000..65bdec0 --- /dev/null +++ b/src/CoincidenceEventTimeView/CoincidenceEventTimeView.cpp @@ -0,0 +1,214 @@ +#include "CoincidenceEventTimeView.h" +#include +#include +#include +#include +#include "CustomQwtPlot.h" +#include +#include "csv.h" +#include +#include +#include "BusyIndicator.h" +#include +#include +#include +#include +#include +struct SpectrumData +{ + int eventId;//事件ID + int board_id; + int channel_id; + double energy; + uint64_t timestamp; +}; + + +CoincidenceEventTimeView::CoincidenceEventTimeView(QWidget *parent) : + MeasureAnalysisView(parent) +{ + this->setViewType(PlotFrame); + + _plot = new CustomQwtPlot(); + QVBoxLayout* layout = new QVBoxLayout(this); + layout->addWidget(_plot); + this->_menu = new QMenu(this); + setupMenu(); + _plot->setCanvasBackground(Qt::white); + QwtPlotCanvas* canvas = qobject_cast(_plot->canvas()); + canvas->setFrameStyle(QFrame::NoFrame); + + QFont font = this->font(); + font.setBold(false); + QwtText x_label = QStringLiteral(u"符合事件初级粒子时间"); + QwtText y_label = QStringLiteral(u"符合事件序号"); + x_label.setFont(font); + y_label.setFont(font); + _plot->setAxisTitle(QwtPlot::xBottom, x_label); + _plot->setAxisTitle(QwtPlot::yLeft, y_label); + + _plot->setAxisAutoScale(QwtPlot::xBottom, true); + _plot->setAxisAutoScale(QwtPlot::yLeft, true); + _plot->enableAxis(QwtPlot::xBottom); + _plot->enableAxis(QwtPlot::yLeft); + _plot->SetAxisDragScale(QwtPlot::xBottom, true); + + _curve = new QwtPlotCurve(); + _curve->setStyle(QwtPlotCurve::Lines); + _curve->setPen(QPen(QColor(23, 229, 238), 2)); + _plot->AddCurve(_curve); + + _busy_indicator = new BusyIndicator(this); +} + +CoincidenceEventTimeView::~CoincidenceEventTimeView() +{ +} + +void CoincidenceEventTimeView::InitViewWorkspace(const QString &project_name) +{ + Q_UNUSED(project_name); +} + +void CoincidenceEventTimeView::SetAnalyzeDataFilename(const QMap &data_files_set) +{ + _data_filenames.clear(); + + for (const QVariant& file_value : data_files_set) { + QString filename = file_value.toString(); + if (!filename.isEmpty() && QFileInfo(filename).exists()) { + _data_filenames.append(filename); + } + } + + if (!_data_filenames.isEmpty()) { + loadAndProcess(); + } +} + + +void CoincidenceEventTimeView::loadAndProcess() +{ + auto functionToRun = [this]() { + if (_data_filenames.isEmpty()) return; + + _busy_indicator->Start(); + + std::vector rawData; + + for (const QString& filename : _data_filenames) { + io::CSVReader<5> in(QStrToSysPath(filename)); + in.read_header(io::ignore_extra_column, + QString(QStringLiteral(u"事件ID")).toStdString(), + QString(QStringLiteral(u"板卡号")).toStdString(), + QString(QStringLiteral(u"通道号")).toStdString(), + QString(QStringLiteral(u"能量(KeV)")).toStdString(), + QString(QStringLiteral(u"时间计数")).toStdString()); + + int eventId,board, channel; + double energy; + unsigned long long time_count; + while (in.read_row(eventId,board, channel, energy, time_count)) { + SpectrumData sd; + sd.eventId = eventId; + sd.board_id = board; + sd.channel_id = channel; + sd.energy = energy; + sd.timestamp = time_count; + rawData.push_back(sd); + } + } + + if (!rawData.empty()) { + std::sort(rawData.begin(), rawData.end(), + [](const SpectrumData& a, const SpectrumData& b) { + return a.eventId < b.eventId; + }); + } + + + if (rawData.empty()) { + _busy_indicator->Stop(); + return; + } + + + int eventId = 0; + QList SpectrumDataList; + for (const auto& spdt : rawData) + { + // 第一个事件是初级粒子 + const auto& firstParticle = spdt; + int boardId = firstParticle.board_id + 1; + int channelId = firstParticle.channel_id + 1; + if(firstParticle.eventId == eventId) continue; + eventId = firstParticle.eventId; + if (boardId >= 1 && boardId <= 8 && channelId >= 1 && channelId <= 4) { + SpectrumDataList.append(spdt); + } + } + + QVector vx, vy; + int ncount = 0; + for(const auto &spdt : SpectrumDataList) + { + ncount++; + vx << spdt.timestamp; + vy << ncount; + } + + if (vx.isEmpty()) { + _busy_indicator->Stop(); + return; + } + + double dmaxx = *std::max_element(vx.begin(), vx.end()); + double dmaxy = *std::max_element(vy.begin(), vy.end()); + + QMetaObject::invokeMethod(this, [this, vx, vy, dmaxx, dmaxy]() { + _curve->setSamples(vx, vy); + _plot->SetAxisInitRange(QwtPlot::yLeft,0.0f, dmaxy); + _plot->SetAxisInitRange(QwtPlot::xBottom,0.0f, dmaxx); + _plot->replot(); + _busy_indicator->Stop(); + }, Qt::QueuedConnection); + }; + + QThread* load_thread = QThread::create(functionToRun); + load_thread->start(); +} + + +void CoincidenceEventTimeView::showEvent(QShowEvent *e) +{ + Q_UNUSED(e); + if (_busy_indicator) { + _busy_indicator->setGeometry(this->rect()); + this->update(); + } +} + +void CoincidenceEventTimeView::setupMenu() +{ + this->setContextMenuPolicy(Qt::CustomContextMenu); + connect(this, &CoincidenceEventTimeView::customContextMenuRequested, [this](const QPoint& pos) { + this->_menu->exec(this->mapToGlobal(pos)); + }); + QAction* action_plot_reset = this->_menu->addAction(QStringLiteral(u"还原")); + action_plot_reset->setObjectName("plot_reset"); + connect(action_plot_reset, &QAction::triggered, [this]() { + this->_plot->ResetPlot(); + }); + this->_menu->addSeparator(); + QAction* action_plot_config = this->_menu->addAction(QStringLiteral(u"图表配置")); + action_plot_config->setObjectName("plot_config"); + connect(action_plot_config, &QAction::triggered, this, &CoincidenceEventTimeView::onActionPlotConfigure); + this->_menu->addSeparator(); +} + +void CoincidenceEventTimeView::onActionPlotConfigure() +{ + +} + + diff --git a/src/CoincidenceEventTimeView/CoincidenceEventTimeView.h b/src/CoincidenceEventTimeView/CoincidenceEventTimeView.h new file mode 100644 index 0000000..75de489 --- /dev/null +++ b/src/CoincidenceEventTimeView/CoincidenceEventTimeView.h @@ -0,0 +1,37 @@ +#ifndef COINCIDENCEEVENTTIMEVIEW_H +#define COINCIDENCEEVENTTIMEVIEW_H + +#include "MeasureAnalysisView.h" +#include +class CustomQwtPlot; +class QwtPlotCurve; +class BusyIndicator; + +class CoincidenceEventTimeView : public MeasureAnalysisView +{ + Q_OBJECT +public: + explicit CoincidenceEventTimeView(QWidget *parent = nullptr); + virtual ~CoincidenceEventTimeView(); + virtual void InitViewWorkspace(const QString& project_name) override final; + virtual void SetAnalyzeDataFilename(const QMap& data_files_set) override; + +protected: + virtual void showEvent(QShowEvent* e) override final; + +private: + void loadAndProcess(); // 读取CSV,执行符合处理,绘制能谱折线图 + void setupMenu(); +private slots: + void onActionPlotConfigure(); +private: + BusyIndicator* _busy_indicator = nullptr; + CustomQwtPlot* _plot = nullptr; + QwtPlotCurve* _curve = nullptr; + QStringList _data_filenames; + QMenu* _menu = nullptr; +}; + +#endif // COINCIDENCEEVENTTIMEVIEW_H + + diff --git a/src/ConformToTheEnergySpectrum/ConformToTheEnergySpectrum.cpp b/src/ConformToTheEnergySpectrum/ConformToTheEnergySpectrum.cpp index 075b18b..6216766 100644 --- a/src/ConformToTheEnergySpectrum/ConformToTheEnergySpectrum.cpp +++ b/src/ConformToTheEnergySpectrum/ConformToTheEnergySpectrum.cpp @@ -116,25 +116,25 @@ void ConformToTheEnergySpectrum::loadAndProcess() return; } -// const uint64_t TIME_WINDOW_NS = 50; -// const int MIN_ORDER = 2; -// const int MAX_ORDER = 9; -// std::vector coincidences = processCoincidence(rawData, TIME_WINDOW_NS, MIN_ORDER, MAX_ORDER); + // const uint64_t TIME_WINDOW_NS = 50; + // const int MIN_ORDER = 2; + // const int MAX_ORDER = 9; + // std::vector coincidences = processCoincidence(rawData, TIME_WINDOW_NS, MIN_ORDER, MAX_ORDER); -// if (coincidences.empty()) { -// _busy_indicator->Stop(); -// return; -// } + // if (coincidences.empty()) { + // _busy_indicator->Stop(); + // return; + // } -// const int STEP = 1; -// std::map hist; + // const int STEP = 1; + // std::map hist; -// for (const auto& ev : coincidences) { -// for (const auto& spdt : ev.events) { -// int idx = static_cast(spdt.energy) / STEP; -// hist[idx] += 1.0; -// } -// } + // for (const auto& ev : coincidences) { + // for (const auto& spdt : ev.events) { + // int idx = static_cast(spdt.energy) / STEP; + // hist[idx] += 1.0; + // } + // } const int STEP = 1; std::map hist; diff --git a/src/EnergyCountPeakFitView/EnergyCountPeakFitView.cpp b/src/EnergyCountPeakFitView/EnergyCountPeakFitView.cpp index 86e28d4..2725142 100644 --- a/src/EnergyCountPeakFitView/EnergyCountPeakFitView.cpp +++ b/src/EnergyCountPeakFitView/EnergyCountPeakFitView.cpp @@ -225,9 +225,9 @@ void EnergyCountPeakFitView::setupMenu() this->_plot->ResetPlot(); }); this->_menu->addSeparator(); - QAction* action_set_curve_show = this->_menu->addAction(QStringLiteral(u"选择曲线")); - action_set_curve_show->setObjectName("curve_show_setting"); - connect(action_set_curve_show, &QAction::triggered, this, &EnergyCountPeakFitView::onActionCurveShowSetting); + //QAction* action_set_curve_show = this->_menu->addAction(QStringLiteral(u"选择曲线")); + //action_set_curve_show->setObjectName("curve_show_setting"); + //connect(action_set_curve_show, &QAction::triggered, this, &EnergyCountPeakFitView::onActionCurveShowSetting); QAction* action_plot_config = this->_menu->addAction(QStringLiteral(u"图表配置")); action_plot_config->setObjectName("plot_config"); connect(action_plot_config, &QAction::triggered, this, &EnergyCountPeakFitView::onActionPlotConfigure); @@ -235,8 +235,8 @@ void EnergyCountPeakFitView::setupMenu() this->_menu->addSeparator(); QAction* action_refit_rect = this->_menu->addAction(QStringLiteral(u"重新拟合当前区域")); connect(action_refit_rect, &QAction::triggered, this, &EnergyCountPeakFitView::onActionRefitCurrentRect); - QAction* action_save_fit = this->_menu->addAction(QStringLiteral(u"保存当前拟合结果")); - connect(action_save_fit, &QAction::triggered, this, &EnergyCountPeakFitView::onActionSaveCurrentFit); + //QAction* action_save_fit = this->_menu->addAction(QStringLiteral(u"保存当前拟合结果")); + //connect(action_save_fit, &QAction::triggered, this, &EnergyCountPeakFitView::onActionSaveCurrentFit); QAction* action_show_history = this->_menu->addAction(QStringLiteral(u"峰拟合结果")); connect(action_show_history, &QAction::triggered, this, &EnergyCountPeakFitView::onActionShowFitHistory); @@ -244,8 +244,8 @@ void EnergyCountPeakFitView::setupMenu() QAction* action_delete_hovered_rect = this->_menu->addAction(QStringLiteral(u"删除当前框选区域")); connect(action_delete_hovered_rect, &QAction::triggered, this, &EnergyCountPeakFitView::onActionDeleteHoveredRect); - QAction* action_hint = this->_menu->addAction(QStringLiteral(u"框选提示:按住 Ctrl 键并拖动左键")); - action_hint->setEnabled(false); + //QAction* action_hint = this->_menu->addAction(QStringLiteral(u"框选提示:按住 Ctrl 键并拖动左键")); + //action_hint->setEnabled(false); } void EnergyCountPeakFitView::loadDataFromFile(const QString& data_name, const QString& filename) @@ -390,8 +390,8 @@ bool EnergyCountPeakFitView::eventFilter(QObject* watched, QEvent* event) // 按下 Ctrl+左键 开始框选 if (event->type() == QEvent::MouseButtonPress && - me->button() == Qt::LeftButton && - (me->modifiers() & Qt::ControlModifier)) { + me->button() == Qt::LeftButton /*&&*/ + /*(me->modifiers() & Qt::ControlModifier)*/) { startSelection(me->pos()); return true; @@ -485,7 +485,7 @@ void EnergyCountPeakFitView::finishSelection() if (roiX.size() >= 3) { QStringList algorithms; - algorithms << QStringLiteral(u"光子峰拟合算法"); + algorithms << QStringLiteral(u"y=A*exp(-pow(x-P,2)/(2*pow(delt,2))) + H/(1+exp((x-P)/W)) + C"); bool ok = false; QString selected = QInputDialog::getItem(this, QStringLiteral(u"选择拟合算法"), @@ -494,7 +494,7 @@ void EnergyCountPeakFitView::finishSelection() 0, false, &ok); - if (ok && selected == QStringLiteral(u"光子峰拟合算法")) + if (ok && selected == QStringLiteral(u"y=A*exp(-pow(x-P,2)/(2*pow(delt,2))) + H/(1+exp((x-P)/W)) + C")) { arma::vec armaRoiX(roiX.size()), armaRoiY(roiY.size()); for (int i = 0; i < roiX.size(); ++i) { diff --git a/src/EnergyCountPeakFitView/PlotRectItem.cpp b/src/EnergyCountPeakFitView/PlotRectItem.cpp index ac32b93..41f645c 100644 --- a/src/EnergyCountPeakFitView/PlotRectItem.cpp +++ b/src/EnergyCountPeakFitView/PlotRectItem.cpp @@ -82,7 +82,8 @@ void PlotRectItem::draw(QPainter *painter, painter->setRenderHint(QPainter::TextAntialiasing); // 构建文本内容 - QString text = QString("峰位: %1 keV\n" + QString text = QString( + "峰位: %1 keV\n" "FWHM: %2\n" "面积: %3\n" "本底: %4") @@ -92,7 +93,7 @@ void PlotRectItem::draw(QPainter *painter, .arg(m_baseline, 0, 'f', 2); // 计算文本位置:矩形右上角 + 偏移量 - QPoint textPos(x2 + 10, y2); + QPoint textPos(x2 + 20, y2 + 10); // 绘制半透明背景框(增强可读性) QFont font = painter->font(); diff --git a/src/MeasureAnalysisTreeView.cpp b/src/MeasureAnalysisTreeView.cpp index 460de7f..d4a9084 100644 --- a/src/MeasureAnalysisTreeView.cpp +++ b/src/MeasureAnalysisTreeView.cpp @@ -276,6 +276,24 @@ void MeasureAnalysisTreeView::onNodeDoubleClicked(const QModelIndex& index) data_files_set[QStringLiteral(u"反符合粒子数据")] = file_name; } } break; + case AnalysisType::CoincidenceEventTimeView: { + MeasureAnalysisProjectModel* project_model = _model->GetProjectModel(project_name); + if (project_model) { + auto file_name_list = project_model->GetTimeWinConformEnergyDataFilenameList(project_model->GetConformTimeWin()); + for (auto it = file_name_list.constBegin(); it!=file_name_list.constEnd(); ++it) { + data_files_set[QString::number(it.key())] = it.value(); + } + } + } break; + case AnalysisType::NuclideAnalysisView: { + MeasureAnalysisProjectModel* project_model = _model->GetProjectModel(project_name); + if (project_model) { + auto all_ch_energy_count_file_name = project_model->GetAllChannelEnergyTotalCountDataFilename(); + if (!all_ch_energy_count_file_name.isEmpty()) { + data_files_set[QStringLiteral(u"核素分析")] = all_ch_energy_count_file_name; + } + } + } break; default: break; } diff --git a/src/MeasureAnalysisView.cpp b/src/MeasureAnalysisView.cpp index de1c907..b31a05e 100644 --- a/src/MeasureAnalysisView.cpp +++ b/src/MeasureAnalysisView.cpp @@ -11,6 +11,8 @@ #include "TwoDSpectralCompliance.h" #include "ConformToTheEnergySpectrum.h" #include "AntiConformEnergySpectrumView.h" +#include "CoincidenceEventTimeView.h" +#include "NuclideAnalysisView.h" #include MeasureAnalysisView* MeasureAnalysisView::NewAnalyzeView(AnalysisType view_type) @@ -82,8 +84,8 @@ MeasureAnalysisView* MeasureAnalysisView::NewAnalyzeView(AnalysisType view_type) new_view->setDeleteOnClose(false); } break; case AnalysisType::NuclideAnalysisView: { - // new_view = new MeasureAnalysisDataTableView; - // new_view->setDeleteOnClose(false); + new_view = new NuclideAnalysisView; + new_view->setDeleteOnClose(false); } break; case AnalysisType::ParticleInTimeView: { new_view = new ParticleInjectTimeAnalysisView; @@ -94,8 +96,8 @@ MeasureAnalysisView* MeasureAnalysisView::NewAnalyzeView(AnalysisType view_type) new_view->setDeleteOnClose(false); } break; case AnalysisType::CoincidenceEventTimeView: { - // new_view = new MeasureAnalysisParticleCountPlotView; - // new_view->setDeleteOnClose(false); + new_view = new CoincidenceEventTimeView; + new_view->setDeleteOnClose(false); } break; case AnalysisType::CoincidenceParticleEnergySpectrumView: { new_view = new ConformToTheEnergySpectrum; @@ -105,6 +107,7 @@ MeasureAnalysisView* MeasureAnalysisView::NewAnalyzeView(AnalysisType view_type) new_view = new AntiConformEnergySpectrumView; new_view->setDeleteOnClose(false); } break; + default: break; } diff --git a/src/NuclideAnalysisView/NuclideAnalysisView.cpp b/src/NuclideAnalysisView/NuclideAnalysisView.cpp new file mode 100644 index 0000000..4115188 --- /dev/null +++ b/src/NuclideAnalysisView/NuclideAnalysisView.cpp @@ -0,0 +1,138 @@ +#include "NuclideAnalysisView.h" +#include "CustomQwtPlot.h" +#include "csv.h" +#include +#include +#include +#include +#include "MeasureAnalysisProjectModel.h" +#include +#include +#include +#include +NuclideAnalysisView::NuclideAnalysisView(QWidget* parent) + : MeasureAnalysisView { parent } +{ + this->setViewType(PlotFrame); + QHBoxLayout* layout = new QHBoxLayout(this); + this->_plot = new CustomQwtPlot(this); + layout->addWidget(this->_plot); + setupPlot(); + this->_menu = new QMenu(this); + setupMenu(); +} + +NuclideAnalysisView::~NuclideAnalysisView() +{ + LOG_DEBUG(QStringLiteral(u"%1析构.").arg(this->GetViewName())); +} + +void NuclideAnalysisView::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; + QDir project_dir(project_model->GetProjectDir()); + _workspace = project_dir.filePath(this->GetViewName()); + if (!QDir(_workspace).exists()) + project_dir.mkpath(_workspace); +} + +void NuclideAnalysisView::SetAnalyzeDataFilename(const QMap& data_files_set) +{ + if (!data_files_set.isEmpty()) { + const QString& data_name = data_files_set.firstKey(); + const QString& data_filename = data_files_set.first().toString(); + if (QFileInfo(data_filename).exists()) { + loadDataFromFile(data_name, data_filename); + } + } +} + +void NuclideAnalysisView::setupPlot() +{ + _plot->setCanvasBackground(Qt::white); + QwtPlotCanvas* canvas = qobject_cast(_plot->canvas()); + canvas->setFrameStyle(QFrame::NoFrame); + QFont font = this->font(); + font.setBold(false); + QwtText energy_label = QStringLiteral(u"能量(KeV)"); + energy_label.setFont(font); + QwtText count_label = QStringLiteral(u"计数"); + count_label.setFont(font); + _plot->setAxisTitle(QwtPlot::xBottom, energy_label); + _plot->setAxisTitle(QwtPlot::yLeft, count_label); + // 设置轴自动缩放 + _plot->setAxisAutoScale(QwtPlot::xBottom, true); + _plot->setAxisAutoScale(QwtPlot::yLeft, true); + _plot->enableAxis(QwtPlot::xBottom); + _plot->enableAxis(QwtPlot::yLeft); + _plot->SetAxisDragScale(QwtPlot::xBottom, true); + // 启用鼠标追踪 + _plot->canvas()->setMouseTracking(true); +} + +void NuclideAnalysisView::setupMenu() +{ + this->setContextMenuPolicy(Qt::CustomContextMenu); + connect(this, &NuclideAnalysisView::customContextMenuRequested, [this](const QPoint& pos) { + this->_menu->exec(this->mapToGlobal(pos)); + }); + QAction* action_plot_reset = this->_menu->addAction(QStringLiteral(u"还原")); + action_plot_reset->setObjectName("plot_reset"); + connect(action_plot_reset, &QAction::triggered, [this]() { + this->_plot->ResetPlot(); + }); + this->_menu->addSeparator(); + QAction* action_plot_config = this->_menu->addAction(QStringLiteral(u"图表配置")); + action_plot_config->setObjectName("plot_config"); + connect(action_plot_config, &QAction::triggered, this, &NuclideAnalysisView::onActionPlotConfigure); + this->_menu->addSeparator(); + +} + +void NuclideAnalysisView::loadDataFromFile(const QString& data_name, const QString& filename) +{ + // 加载新数据前清空旧数据 + _plot->replot(); + + std::string address_str = QString(QStringLiteral(u"能量(KeV)")).toStdString(); + std::string count_str = QString(QStringLiteral(u"计数")).toStdString(); + io::CSVReader< + 2, + io::trim_chars<' ', '\t'>, + io::double_quote_escape<',', '"'>, + io::throw_on_overflow, + io::empty_line_comment> + reader(QStrToSysPath(filename)); + reader.read_header(io::ignore_extra_column, address_str, count_str); + + double energy; + unsigned long long energy_count; + QVector x, y; + while (reader.read_row(energy, energy_count)) { + x.push_back(energy); + y.push_back(energy_count); + if(_x_max < energy) + _x_max = energy; + if(_y_max < energy_count) + _y_max = energy_count; + } + + _plot->SetAxisInitRange(QwtPlot::xBottom,0.0f,_x_max); + _plot->SetAxisInitRange(QwtPlot::yLeft,0.0f,_y_max); + + // 绘制原始数据曲线 + QwtPlotCurve* curve = new QwtPlotCurve(QStringLiteral(u"原始数据")); + curve->setPen(QPen(Qt::gray, 2)); // 原始数据统一灰色 + curve->setSamples(x, y); + _plot->AddCurve(curve,false); +} + +void NuclideAnalysisView::onActionPlotConfigure() +{ + +} \ No newline at end of file diff --git a/src/NuclideAnalysisView/NuclideAnalysisView.h b/src/NuclideAnalysisView/NuclideAnalysisView.h new file mode 100644 index 0000000..260b2b9 --- /dev/null +++ b/src/NuclideAnalysisView/NuclideAnalysisView.h @@ -0,0 +1,33 @@ +#ifndef NUCLIDEANALYSISVIEW_H +#define NUCLIDEANALYSISVIEW_H +#include +#include +#include +#include +#include +class CustomQwtPlot; +class NuclideAnalysisView : public MeasureAnalysisView +{ + Q_OBJECT +public: + NuclideAnalysisView(QWidget *parent = nullptr); + virtual ~NuclideAnalysisView(); + virtual void InitViewWorkspace(const QString& project_name) override final; + virtual void SetAnalyzeDataFilename(const QMap& data_files_set); + +private: + void setupPlot(); + void setupMenu(); + void loadDataFromFile(const QString &data_name, const QString& filename); +private slots: + void onActionPlotConfigure(); + +private: + CustomQwtPlot* _plot = nullptr; + QString _workspace; + QMenu* _menu = nullptr; + + int _x_max = 0; + int _y_max = 0; +}; +#endif // NUCLIDEANALYSISVIEW_H \ No newline at end of file diff --git a/src/NuclideLib/NuclideLib.cpp b/src/NuclideLib/NuclideLib.cpp index 6573f04..5359902 100644 --- a/src/NuclideLib/NuclideLib.cpp +++ b/src/NuclideLib/NuclideLib.cpp @@ -17,7 +17,7 @@ void ButtonDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option if (index.column() == 7) { QStyleOptionButton button; button.rect = option.rect; - button.text = "核素发射射线信息"; + button.text = QStringLiteral(u"核素发射射线信息"); button.state = QStyle::State_Enabled; if (option.state & QStyle::State_MouseOver) button.state |= QStyle::State_MouseOver; @@ -63,8 +63,9 @@ NuclideLibManage::NuclideLibManage(QWidget *parent) : ui->tableView->setAlternatingRowColors(true); ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows); ui->tableView->setFocusPolicy(Qt::NoFocus); + ui->tableView->verticalHeader()->setVisible(false); - QString dbPath = QCoreApplication::applicationDirPath() + "/nuclideLib.db"; // 绝对路径(推荐) + QString dbPath = QCoreApplication::applicationDirPath() + "/nuclideLib.db"; qDebug()< 0) { - QMessageBox::information(this, "成功", "核素添加成功!"); + QMessageBox::information(this, QStringLiteral(u"成功"), QStringLiteral(u"核素添加成功!")); loadNuclideData(); } else { - QMessageBox::warning(this, "失败", "添加失败:" + SqliteManager::instance().lastError()); + QMessageBox::warning(this, QStringLiteral(u"失败"), QStringLiteral(u"添加失败:") + SqliteManager::instance().lastError()); } } } @@ -170,7 +171,7 @@ void NuclideLibManage::on_pushButton_edit_clicked() { QModelIndexList selected = ui->tableView->selectionModel()->selectedRows(); if (selected.isEmpty()) { - QMessageBox::information(this, "提示", "请先选择要修改的核素行!"); + QMessageBox::information(this, QStringLiteral(u"提示"), QStringLiteral(u"请先选择要修改的核素行!")); return; } @@ -199,12 +200,12 @@ void NuclideLibManage::on_pushButton_edit_clicked() ); if (affectedRows > 0) { - QMessageBox::information(this, "成功", "核素修改成功!"); + QMessageBox::information(this, QStringLiteral(u"成功"), QStringLiteral(u"核素修改成功!")); loadNuclideData(); } else if (affectedRows == 0) { - QMessageBox::information(this, "提示", "未修改任何数据!"); + QMessageBox::information(this, QStringLiteral(u"提示"), QStringLiteral(u"未修改任何数据!")); } else { - QMessageBox::warning(this, "失败", "修改失败:" + SqliteManager::instance().lastError()); + QMessageBox::warning(this, QStringLiteral(u"失败"), QStringLiteral(u"修改失败:") + SqliteManager::instance().lastError()); } } } @@ -213,24 +214,24 @@ void NuclideLibManage::on_pushButton_del_clicked() { QModelIndexList selected = ui->tableView->selectionModel()->selectedRows(); if (selected.isEmpty()) { - QMessageBox::information(this, "提示", "请先选择要删除的核素行!"); + QMessageBox::information(this, QStringLiteral(u"提示"), QStringLiteral(u"请先选择要删除的核素行!")); return; } int row = selected.first().row(); QString id = m_model->index(row, 0).data().toString(); - QMessageBox box(QMessageBox::Question, "提示", "确定删除该核素吗?", + QMessageBox box(QMessageBox::Question, QStringLiteral(u"提示"), QStringLiteral(u"确定删除该核素吗?"), QMessageBox::Yes | QMessageBox::No, this); - box.button(QMessageBox::Yes)->setText("确认"); - box.button(QMessageBox::No)->setText("取消"); + box.button(QMessageBox::Yes)->setText(QStringLiteral(u"确认")); + box.button(QMessageBox::No)->setText(QStringLiteral(u"取消")); if (box.exec() != QMessageBox::Yes) return; bool ok = SqliteManager::instance().deleteRow("nuclideLib", "ID = ?", {id}); if (ok) { loadNuclideData(); } else { - QMessageBox::warning(this, "错误", "删除失败:" + SqliteManager::instance().lastError()); + QMessageBox::warning(this, QStringLiteral(u"错误"), QStringLiteral(u"删除失败:") + SqliteManager::instance().lastError()); } } diff --git a/src/NuclideLib/NuclideRayDialog.cpp b/src/NuclideLib/NuclideRayDialog.cpp index f77c8f1..63581a2 100644 --- a/src/NuclideLib/NuclideRayDialog.cpp +++ b/src/NuclideLib/NuclideRayDialog.cpp @@ -23,40 +23,40 @@ NuclideRayDialog::NuclideRayDialog(bool isEdit, const QStringList& rayData, QWid void NuclideRayDialog::initUI() { - setWindowTitle(m_isEdit ? "编辑射线信息" : "添加射线信息"); + setWindowTitle(m_isEdit ? QStringLiteral(u"编辑射线信息") : QStringLiteral(u"添加射线信息")); setFixedSize(450, 300); QFormLayout *formLayout = new QFormLayout(this); // 射线类型下拉框(常用核素射线类型) m_cmbRayType = new QComboBox(this); - m_cmbRayType->addItems({"γ", "β⁻", "β⁺", "α", "X射线", "中子", "电子俘获"}); - formLayout->addRow("射线类型", m_cmbRayType); + m_cmbRayType->addItems({QStringLiteral(u"γ"), QStringLiteral(u"β⁻"), QStringLiteral(u"β⁺"), QStringLiteral(u"α"), QStringLiteral(u"X射线"), QStringLiteral(u"中子"), QStringLiteral(u"电子俘获")}); + formLayout->addRow(QStringLiteral(u"射线类型"), m_cmbRayType); m_leRayMev = new QLineEdit(this); - m_leRayMev->setPlaceholderText("例如:1.332 MeV"); - formLayout->addRow("射线能量", m_leRayMev); + m_leRayMev->setPlaceholderText(QStringLiteral(u"例如:1.332 MeV")); + formLayout->addRow(QStringLiteral(u"射线能量"), m_leRayMev); m_leRayMevUnc = new QLineEdit(this); - m_leRayMevUnc->setPlaceholderText("例如:0.001 MeV"); - formLayout->addRow("能量不确定度", m_leRayMevUnc); + m_leRayMevUnc->setPlaceholderText(QStringLiteral(u"例如:0.001 MeV")); + formLayout->addRow(QStringLiteral(u"能量不确定度"), m_leRayMevUnc); m_leBranchRatio = new QLineEdit(this); - m_leBranchRatio->setPlaceholderText("例如:0.9998"); + m_leBranchRatio->setPlaceholderText(QStringLiteral(u"例如:0.9998")); formLayout->addRow("分支比", m_leBranchRatio); m_leBranchRatioUnc = new QLineEdit(this); - m_leBranchRatioUnc->setPlaceholderText("例如:0.0001"); - formLayout->addRow("分支比不确定度", m_leBranchRatioUnc); + m_leBranchRatioUnc->setPlaceholderText(QStringLiteral(u"例如:0.0001")); + formLayout->addRow(QStringLiteral(u"分支比不确定度"), m_leBranchRatioUnc); // 主射线标识下拉框 m_cmbMainRayIdent = new QComboBox(this); - m_cmbMainRayIdent->addItems({"是", "否"}); - formLayout->addRow("是否为主射线", m_cmbMainRayIdent); + m_cmbMainRayIdent->addItems({QStringLiteral(u"是"), QStringLiteral(u"否")}); + formLayout->addRow(QStringLiteral(u"是否为主射线"), m_cmbMainRayIdent); m_leJiahePeak = new QLineEdit(this); - m_leJiahePeak->setPlaceholderText("无则留空"); - formLayout->addRow("加和峰", m_leJiahePeak); + m_leJiahePeak->setPlaceholderText(QStringLiteral(u"无则留空")); + formLayout->addRow(QStringLiteral(u"加和峰"), m_leJiahePeak); // 按钮盒 QDialogButtonBox *btnBox = new QDialogButtonBox( @@ -77,15 +77,15 @@ bool NuclideRayDialog::validateInput() { // 必填项校验 if (m_leRayMev->text().trimmed().isEmpty()) { - QMessageBox::warning(this, "输入错误", "射线能量不能为空!"); + QMessageBox::warning(this, QStringLiteral(u"输入错误"), QStringLiteral(u"射线能量不能为空!")); return false; } if (m_leRayMevUnc->text().trimmed().isEmpty()) { - QMessageBox::warning(this, "输入错误", "能量不确定度不能为空!"); + QMessageBox::warning(this, QStringLiteral(u"输入错误"), QStringLiteral(u"能量不确定度不能为空!")); return false; } if (m_leBranchRatioUnc->text().trimmed().isEmpty()) { - QMessageBox::warning(this, "输入错误", "分支比不确定度不能为空!"); + QMessageBox::warning(this, QStringLiteral(u"输入错误"), QStringLiteral(u"分支比不确定度不能为空!")); return false; } @@ -95,21 +95,21 @@ bool NuclideRayDialog::validateInput() QString mevText = m_leRayMev->text().trimmed().replace(QRegExp("[^0-9.]"), ""); mevText.toDouble(&ok); if (!ok) { - QMessageBox::warning(this, "输入错误", "射线能量必须为有效数字!"); + QMessageBox::warning(this, QStringLiteral(u"输入错误"), QStringLiteral(u"射线能量必须为有效数字!")); return false; } QString mevUncText = m_leRayMevUnc->text().trimmed().replace(QRegExp("[^0-9.]"), ""); mevUncText.toDouble(&ok); if (!ok) { - QMessageBox::warning(this, "输入错误", "能量不确定度必须为有效数字!"); + QMessageBox::warning(this, QStringLiteral(u"输入错误"), QStringLiteral(u"能量不确定度必须为有效数字!")); return false; } QString ratioUncText = m_leBranchRatioUnc->text().trimmed().replace(QRegExp("[^0-9.]"), ""); ratioUncText.toDouble(&ok); if (!ok) { - QMessageBox::warning(this, "输入错误", "分支比不确定度必须为有效数字!"); + QMessageBox::warning(this, QStringLiteral(u"输入错误"), QStringLiteral(u"分支比不确定度必须为有效数字!")); return false; } diff --git a/src/NuclideLib/NuclideRayListDialog.cpp b/src/NuclideLib/NuclideRayListDialog.cpp index b1009c2..8424927 100644 --- a/src/NuclideLib/NuclideRayListDialog.cpp +++ b/src/NuclideLib/NuclideRayListDialog.cpp @@ -8,7 +8,7 @@ void RayButtonDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opt // 绘制编辑按钮 QStyleOptionButton editBtn; editBtn.rect = QRect(option.rect.x(), option.rect.y() + 2, 60, option.rect.height() - 4); - editBtn.text = "编辑"; + editBtn.text = QStringLiteral(u"编辑"); editBtn.state = QStyle::State_Enabled; if (option.state & QStyle::State_MouseOver) editBtn.state |= QStyle::State_MouseOver; @@ -17,7 +17,7 @@ void RayButtonDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opt // 绘制删除按钮 QStyleOptionButton delBtn; delBtn.rect = QRect(option.rect.x() + 70, option.rect.y() + 2, 60, option.rect.height() - 4); - delBtn.text = "删除"; + delBtn.text = QStringLiteral(u"删除"); delBtn.state = QStyle::State_Enabled; if (option.state & QStyle::State_MouseOver) delBtn.state |= QStyle::State_MouseOver; @@ -54,26 +54,27 @@ NuclideRayListDialog::NuclideRayListDialog(const QString& nuclideId, const QStri void NuclideRayListDialog::initUI() { - setWindowTitle(QString("%1 - 射线信息管理").arg(m_nuclideName)); - setFixedSize(900, 500); + setWindowTitle(QStringLiteral(u"%1 - 射线信息管理").arg(m_nuclideName)); + setFixedSize(1100, 500); QVBoxLayout *mainLayout = new QVBoxLayout(this); // 添加按钮 - QPushButton *btnAdd = new QPushButton("添加射线", this); + QPushButton *btnAdd = new QPushButton(QStringLiteral(u"添加射线"), this); connect(btnAdd, &QPushButton::clicked, this, &NuclideRayListDialog::onAddRayClicked); mainLayout->addWidget(btnAdd, 0, Qt::AlignRight); // 射线列表 m_model = new QStandardItemModel(0, 9, this); m_model->setHorizontalHeaderLabels({ - "ID", "射线类型", "能量(MeV)", "能量不确定度", "分支比", - "分支比不确定度", "主射线", "加和峰", "操作" + QStringLiteral(u"ID"), QStringLiteral(u"射线类型"), QStringLiteral(u"能量(MeV)"), QStringLiteral(u"能量不确定度"), QStringLiteral(u"分支比"), + QStringLiteral(u"分支比不确定度"), QStringLiteral(u"主射线"), QStringLiteral(u"加和峰"), QStringLiteral(u"操作") }); QTableView *tableView = new QTableView(this); tableView->setModel(m_model); - tableView->setColumnHidden(0, true); // 隐藏ID列 + tableView->verticalHeader()->setVisible(false); + tableView->setColumnWidth(0, 80); // ID tableView->setColumnWidth(1, 80); // 射线类型 tableView->setColumnWidth(2, 120); // 能量 tableView->setColumnWidth(3, 120); // 能量不确定度 @@ -97,7 +98,7 @@ void NuclideRayListDialog::initUI() mainLayout->addWidget(tableView); // 关闭按钮 - QPushButton *btnClose = new QPushButton("关闭", this); + QPushButton *btnClose = new QPushButton(QStringLiteral(u"关闭"), this); connect(btnClose, &QPushButton::clicked, this, &QDialog::accept); mainLayout->addWidget(btnClose, 0, Qt::AlignRight); } @@ -181,10 +182,10 @@ void NuclideRayListDialog::onAddRayClicked() qint64 newId = SqliteManager::instance().insertRow("nuclideRayInfo", fieldValues); if (newId > 0) { - QMessageBox::information(this, "成功", "射线信息添加成功!"); + QMessageBox::information(this, QStringLiteral(u"成功"), QStringLiteral(u"射线信息添加成功!")); loadRayData(); // 刷新列表 } else { - QMessageBox::warning(this, "失败", "添加失败:" + SqliteManager::instance().lastError()); + QMessageBox::warning(this, QStringLiteral(u"失败"), QStringLiteral(u"添加失败:") + SqliteManager::instance().lastError()); } } } @@ -218,12 +219,12 @@ void NuclideRayListDialog::onEditRayClicked(const QModelIndex &index) ); if (affectedRows > 0) { - QMessageBox::information(this, "成功", "射线信息修改成功!"); + QMessageBox::information(this, QStringLiteral(u"成功"), QStringLiteral(u"射线信息修改成功!")); loadRayData(); } else if (affectedRows == 0) { - QMessageBox::information(this, "提示", "未修改任何数据!"); + QMessageBox::information(this, QStringLiteral(u"提示"), QStringLiteral(u"未修改任何数据!")); } else { - QMessageBox::warning(this, "失败", "修改失败:" + SqliteManager::instance().lastError()); + QMessageBox::warning(this, QStringLiteral(u"失败"), QStringLiteral(u"修改失败:") + SqliteManager::instance().lastError()); } } } @@ -233,16 +234,16 @@ void NuclideRayListDialog::onDeleteRayClicked(const QModelIndex &index) int row = index.row(); QString id = m_model->index(row, 0).data().toString(); - QMessageBox box(QMessageBox::Question, "提示", "确定删除该射线信息吗?", + QMessageBox box(QMessageBox::Question, QStringLiteral(u"提示"), QStringLiteral(u"确定删除该射线信息吗?"), QMessageBox::Yes | QMessageBox::No, this); - box.button(QMessageBox::Yes)->setText("确认"); - box.button(QMessageBox::No)->setText("取消"); + box.button(QMessageBox::Yes)->setText(QStringLiteral(u"确认")); + box.button(QMessageBox::No)->setText(QStringLiteral(u"取消")); if (box.exec() != QMessageBox::Yes) return; bool ok = SqliteManager::instance().deleteRow("nuclideRayInfo", "ID = ?", {id}); if (ok) { loadRayData(); } else { - QMessageBox::warning(this, "错误", "删除失败:" + SqliteManager::instance().lastError()); + QMessageBox::warning(this, QStringLiteral(u"错误"), QStringLiteral(u"删除失败:") + SqliteManager::instance().lastError()); } } diff --git a/src/src.pro b/src/src.pro index 1509c70..fcab269 100644 --- a/src/src.pro +++ b/src/src.pro @@ -38,7 +38,10 @@ INCLUDEPATH += \ $${PWD}/2DSpectralCompliance \ $${PWD}/ConformToTheEnergySpectrum \ $${PWD}/NuclideLib \ - $${PWD}/AntiConformEnergySpectrumView + $${PWD}/AntiConformEnergySpectrumView\ + $${PWD}/CoincidenceEventTimeView\ + $${PWD}/NuclideAnalysisView + DEPENDPATH += \ $${PWD}/BusyIndicator \ @@ -57,12 +60,17 @@ DEPENDPATH += \ $${PWD}/2DSpectralCompliance \ $${PWD}/ConformToTheEnergySpectrum \ $${PWD}/NuclideLib \ - $${PWD}/AntiConformEnergySpectrumView + $${PWD}/AntiConformEnergySpectrumView\ + $${PWD}/CoincidenceEventTimeView\ + $${PWD}/NuclideAnalysisView + + SOURCES += \ 2DSpectralCompliance/TwoDSpectralCompliance.cpp \ AboutDlg.cpp \ BusyIndicator/BusyIndicator.cpp \ + CoincidenceEventTimeView/CoincidenceEventTimeView.cpp \ CountRateAnalysisView/CountRateAnalysisView.cpp \ CustomQwtPlot.cpp \ DataProcessWorkPool.cpp \ @@ -79,6 +87,7 @@ SOURCES += \ MeasureDeviceParamsConfigView/DeviceParamsSaveToSysDlg.cpp \ MeasureDeviceParamsConfigView/DeviceParamsTableForm.cpp \ MeasureDeviceParamsConfigView/MeasureDeviceParamsConfigView.cpp \ + NuclideAnalysisView/NuclideAnalysisView.cpp \ NuclideLib/NuclideEditDialog.cpp \ NuclideLib/NuclideRayDialog.cpp \ NuclideLib/NuclideRayListDialog.cpp \ @@ -111,6 +120,7 @@ HEADERS += \ AboutDlg.h \ AnalysisTypeDefine.h \ BusyIndicator/BusyIndicator.h \ + CoincidenceEventTimeView/CoincidenceEventTimeView.h \ CountRateAnalysisView/CountRateAnalysisView.h \ CustomQwtPlot.h \ DataProcessWorkPool.h \ @@ -128,6 +138,7 @@ HEADERS += \ MeasureDeviceParamsConfigView/DeviceParamsSaveToSysDlg.h \ MeasureDeviceParamsConfigView/DeviceParamsTableForm.h \ MeasureDeviceParamsConfigView/MeasureDeviceParamsConfigView.h \ + NuclideAnalysisView/NuclideAnalysisView.h \ NuclideLib/NuclideEditDialog.h \ NuclideLib/NuclideRayDialog.h \ NuclideLib/NuclideRayListDialog.h \