From 814b85d40b0acce6ca34b9da7b1d388ce7c02abe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=B5=B7?= Date: Wed, 13 May 2026 11:29:36 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=8A=A0=E8=BD=BD=E5=8A=A8?= =?UTF-8?q?=E7=94=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TwoDSpectralCompliance.cpp | 8 +- .../AntiConformEnergySpectrumView.cpp | 17 ++- .../CoincidenceEventTimeView.cpp | 29 ++-- .../CountRateAnalysisView.cpp | 16 +-- .../CountRateAnalysisView.h | 1 - .../EnergyCountPeakFitView.h | 126 +++++++++--------- .../ParticleInjectTimeAnalysisView.cpp | 16 ++- .../ParticleTimeDifferenceView.cpp | 18 ++- 8 files changed, 122 insertions(+), 109 deletions(-) diff --git a/src/2DSpectralCompliance/TwoDSpectralCompliance.cpp b/src/2DSpectralCompliance/TwoDSpectralCompliance.cpp index 6329781..cc11a74 100644 --- a/src/2DSpectralCompliance/TwoDSpectralCompliance.cpp +++ b/src/2DSpectralCompliance/TwoDSpectralCompliance.cpp @@ -68,12 +68,14 @@ void TwoDSpectralCompliance::SetAnalyzeDataFilename(const QMapStart(); auto functionToRun = [this, csvFile]() { - _busy_indicator->Start(); readCsv(csvFile); generateSurfaceData(); - updateSpectrogram(); - _busy_indicator->Stop(); + QMetaObject::invokeMethod(this, [this]() { + updateSpectrogram(); + _busy_indicator->Stop(); + }, Qt::QueuedConnection); }; QThread* load_data_thread = QThread::create(functionToRun); load_data_thread->start(); diff --git a/src/AntiConformEnergySpectrumView/AntiConformEnergySpectrumView.cpp b/src/AntiConformEnergySpectrumView/AntiConformEnergySpectrumView.cpp index bad5f93..48198d4 100644 --- a/src/AntiConformEnergySpectrumView/AntiConformEnergySpectrumView.cpp +++ b/src/AntiConformEnergySpectrumView/AntiConformEnergySpectrumView.cpp @@ -83,11 +83,14 @@ void AntiConformEnergySpectrumView::SetAnalyzeDataFilename(const QMapStart(); auto functionToRun = [this]() { - if (_data_filename.isEmpty()) + if (_data_filename.isEmpty()) { + QMetaObject::invokeMethod(this, [this]() { + _busy_indicator->Stop(); + }, Qt::QueuedConnection); return; - - _busy_indicator->Start(); + } std::vector rawData; io::CSVReader<4> in(QStrToSysPath(_data_filename)); @@ -110,7 +113,9 @@ void AntiConformEnergySpectrumView::loadAndProcess() } if (rawData.empty()) { - _busy_indicator->Stop(); + QMetaObject::invokeMethod(this, [this]() { + _busy_indicator->Stop(); + }, Qt::QueuedConnection); return; } @@ -129,7 +134,9 @@ void AntiConformEnergySpectrumView::loadAndProcess() } if (vx.isEmpty()) { - _busy_indicator->Stop(); + QMetaObject::invokeMethod(this, [this]() { + _busy_indicator->Stop(); + }, Qt::QueuedConnection); return; } diff --git a/src/CoincidenceEventTimeView/CoincidenceEventTimeView.cpp b/src/CoincidenceEventTimeView/CoincidenceEventTimeView.cpp index 65bdec0..87d50f4 100644 --- a/src/CoincidenceEventTimeView/CoincidenceEventTimeView.cpp +++ b/src/CoincidenceEventTimeView/CoincidenceEventTimeView.cpp @@ -89,13 +89,15 @@ void CoincidenceEventTimeView::SetAnalyzeDataFilename(const QMapStart(); auto functionToRun = [this]() { - if (_data_filenames.isEmpty()) return; - - _busy_indicator->Start(); - + if (_data_filenames.isEmpty()) { + QMetaObject::invokeMethod(this, [this]() { + _busy_indicator->Stop(); + }, Qt::QueuedConnection); + return; + } std::vector rawData; - for (const QString& filename : _data_filenames) { io::CSVReader<5> in(QStrToSysPath(filename)); in.read_header(io::ignore_extra_column, @@ -126,17 +128,15 @@ void CoincidenceEventTimeView::loadAndProcess() }); } - if (rawData.empty()) { - _busy_indicator->Stop(); + QMetaObject::invokeMethod(this, [this]() { + _busy_indicator->Stop(); + }, Qt::QueuedConnection); return; } - - int eventId = 0; QList SpectrumDataList; - for (const auto& spdt : rawData) - { + for (const auto& spdt : rawData) { // 第一个事件是初级粒子 const auto& firstParticle = spdt; int boardId = firstParticle.board_id + 1; @@ -150,15 +150,16 @@ void CoincidenceEventTimeView::loadAndProcess() QVector vx, vy; int ncount = 0; - for(const auto &spdt : SpectrumDataList) - { + for(const auto &spdt : SpectrumDataList) { ncount++; vx << spdt.timestamp; vy << ncount; } if (vx.isEmpty()) { - _busy_indicator->Stop(); + QMetaObject::invokeMethod(this, [this]() { + _busy_indicator->Stop(); + }, Qt::QueuedConnection); return; } diff --git a/src/CountRateAnalysisView/CountRateAnalysisView.cpp b/src/CountRateAnalysisView/CountRateAnalysisView.cpp index f43a9e7..66675d4 100644 --- a/src/CountRateAnalysisView/CountRateAnalysisView.cpp +++ b/src/CountRateAnalysisView/CountRateAnalysisView.cpp @@ -44,14 +44,14 @@ void CountRateAnalysisView::InitViewWorkspace(const QString &project_name) } void CountRateAnalysisView::SetAnalyzeDataFilename(const QMap &data_files_set) { - if(!data_files_set.isEmpty()) - { - auto functionToRun = [this,data_files_set] - { - _busy_indicator->Start(); - m_AllData = getParticleInjectTimeData(data_files_set.first().toString()); - setData(m_AllData); - _busy_indicator->Stop(); + if(!data_files_set.isEmpty()) { + _busy_indicator->Start(); + auto functionToRun = [this,data_files_set] { + QVector data = getParticleInjectTimeData(data_files_set.first().toString()); + QMetaObject::invokeMethod(this, [this, data]() { + setData(data); + _busy_indicator->Stop(); + }, Qt::QueuedConnection); }; QThread* load_data_thread = QThread::create(functionToRun); load_data_thread->start(); diff --git a/src/CountRateAnalysisView/CountRateAnalysisView.h b/src/CountRateAnalysisView/CountRateAnalysisView.h index f4ce0ab..caada6c 100644 --- a/src/CountRateAnalysisView/CountRateAnalysisView.h +++ b/src/CountRateAnalysisView/CountRateAnalysisView.h @@ -44,7 +44,6 @@ private: BusyIndicator* _busy_indicator = nullptr; CustomQwtPlot *plot; QMenu* _menu = nullptr; - QVector m_AllData;//存储的所有的粒子入射时间数据 }; #endif //COUNTRATEANALYSIS_H diff --git a/src/EnergyCountPeakFitView/EnergyCountPeakFitView.h b/src/EnergyCountPeakFitView/EnergyCountPeakFitView.h index 0bf2867..272ce0f 100644 --- a/src/EnergyCountPeakFitView/EnergyCountPeakFitView.h +++ b/src/EnergyCountPeakFitView/EnergyCountPeakFitView.h @@ -1,74 +1,76 @@ #ifndef ENERGYCOUNTPEAKFITVIEW_H #define ENERGYCOUNTPEAKFITVIEW_H -#include -#include +#include "PeakFitParamsDialog.h" #include -#include -#include -#include // 新增 -#include // 新增 #include #include #include -#include "PeakFitParamsDialog.h" +#include +#include // 新增 +#include +#include +#include +#include // 新增 -#include "DataCalcProcess/FindPeaksBySvd.h" -#include "DataCalcProcess/NolinearLeastSquaresCurveFit.h" #include "DataCalcProcess/AdaptiveSimpsonIntegrate.h" +#include "DataCalcProcess/FindPeaksBySvd.h" #include "DataCalcProcess/MathModelDefine.h" +#include "DataCalcProcess/NolinearLeastSquaresCurveFit.h" -struct PeakFitResult -{ - double center; // 峰中心能量 (keV) - double amplitude; // 高斯振幅 - double sigma; // 高斯宽度 - double fwhm; // 半高宽 = sigma * 2.355 - double area; // 峰面积(积分) - double baseline; // 常数项 C - double sigmoidH; // Sigmoid 项高度 H - double sigmoidW; // Sigmoid 项宽度 W +struct PeakFitResult { + double center; // 峰中心能量 (keV) + double amplitude; // 高斯振幅 + double sigma; // 高斯宽度 + double fwhm; // 半高宽 = sigma * 2.355 + double area; // 峰面积(积分) + double baseline; // 常数项 C + double sigmoidH; // Sigmoid 项高度 H + double sigmoidW; // Sigmoid 项宽度 W }; struct FitCurveData { - double amplitude; // 峰幅度 - double sigma; // 高斯sigma - double sigmoidH; // Sigmoid高度 - double sigmoidW; // Sigmoid宽度 - double baseline; // 本底 - double center; // 峰中心 - double xMin; // 曲线X范围最小值 - double xMax; // 曲线X范围最大值 - QRectF selectionRect; //关联的框选区域 + double amplitude; // 峰幅度 + double sigma; // 高斯sigma + double sigmoidH; // Sigmoid高度 + double sigmoidW; // Sigmoid宽度 + double baseline; // 本底 + double center; // 峰中心 + double xMin; // 曲线X范围最小值 + double xMax; // 曲线X范围最大值 + QRectF selectionRect; // 关联的框选区域 - double fwhm; // 半高宽 - double area; // 峰面积 + double fwhm; // 半高宽 + double area; // 峰面积 }; struct PeakFitHistoryItem { QDateTime timestamp; - QList curveList; //存储多条曲线 + QList curveList; // 存储多条曲线 - QJsonObject toJson() const; - static PeakFitHistoryItem fromJson(const QJsonObject& obj); + QJsonObject toJson() const; + static PeakFitHistoryItem fromJson(const QJsonObject& obj); }; struct CurrentFitRecord { - PeakFitResult result; // 拟合结果 - arma::vec params; // 完整拟合参数 - double xMin; // X范围最小值 - double xMax; // X范围最大值 - int historyIndex; // 对应_fitHistoryList中的索引,-1表示未保存 - CurrentFitRecord() : historyIndex(-1) {} // 构造函数初始化 + PeakFitResult result; // 拟合结果 + arma::vec params; // 完整拟合参数 + double xMin; // X范围最小值 + double xMax; // X范围最大值 + int historyIndex; // 对应_fitHistoryList中的索引,-1表示未保存 + CurrentFitRecord() + : historyIndex(-1) + { + } // 构造函数初始化 }; struct DisplayedCurveRef { int historyIndex; // 对应 _fitHistoryList 的索引 - int curveIndex; // 对应 curveList 的索引 - int curveStartIndex; //对应 _fitCurves 中的起始索引(一条历史曲线对应2条Qwt曲线:拟合+本底) - int rectIndex; //对应 _selectionRectItems 中的索引 + int curveIndex; // 对应 curveList 的索引 + int curveStartIndex; // 对应 _fitCurves 中的起始索引(一条历史曲线对应2条Qwt曲线:拟合+本底) + int rectIndex; // 对应 _selectionRectItems 中的索引 }; -class PlotRectItem; // 前向声明 +class PlotRectItem; // 前向声明 class QMenu; class CustomQwtPlot; class CustomQwtPlotXaxisSelector; @@ -76,11 +78,10 @@ class QwtPlotPicker; class QwtPlotCurve; class BusyIndicator; -class EnergyCountPeakFitView : public MeasureAnalysisView -{ +class EnergyCountPeakFitView : public MeasureAnalysisView { Q_OBJECT public: - EnergyCountPeakFitView(QWidget *parent = nullptr); + EnergyCountPeakFitView(QWidget* parent = nullptr); virtual ~EnergyCountPeakFitView(); virtual void InitViewWorkspace(const QString& project_name) override final; @@ -89,30 +90,30 @@ public: private: void setupPlot(); void setupMenu(); - void loadDataFromFile(const QString &data_name, const QString& filename); - + void loadDataFromFile(const QString& data_name, const QString& filename); void loadHistoryFromFile(); void saveHistoryToFile(); - void saveCurrentFitToHistory(); // 保存当前拟合结果 + void saveCurrentFitToHistory(); // 保存当前拟合结果 void displayFitFromHistory(const PeakFitHistoryItem& item); // 显示历史拟合曲线 - //处理鼠标悬停检测 + // 处理鼠标悬停检测 void updateHoverState(const QPoint& mousePos); - //显示选中的曲线 + // 显示选中的曲线 void displaySelectedCurves(const QList& curves, const QList& refs); private slots: void onActionCurveShowSetting(); void onActionPlotConfigure(); void clearAllSelectionRects(); - void clearFitCurves(); // 清除所有拟合曲线 + void clearFitCurves(); // 清除所有拟合曲线 void onActionSaveCurrentFit(); void onActionShowFitHistory(); void onActionDeleteHoveredRect(); - //重新拟合当前悬停的框选区域 + // 重新拟合当前悬停的框选区域 void onActionRefitCurrentRect(); + protected: - bool eventFilter(QObject* watched, QEvent* event) override; // 事件过滤器 + bool eventFilter(QObject* watched, QEvent* event) override; // 事件过滤器 private: void startSelection(const QPoint& pos); @@ -121,7 +122,7 @@ private: void addSelectionRect(const QRectF& plotRect); void fadeSelectionRectBorders(); -QList performPeakFitting(const QVector& x, const QVector& y/*, const arma::vec* userP0 = nullptr*/); + QList performPeakFitting(const QVector& x, const QVector& y /*, const arma::vec* userP0 = nullptr*/); // 根据拟合参数生成曲线 QwtPlotCurve* createFitCurve(const PeakFitResult& result, double xMin, double xMax, const QString& name); @@ -135,33 +136,30 @@ private: // 手动框选状态 bool _isSelecting = false; QPoint _selectionStart; - QRubberBand* _rubberBand = nullptr; // 原生橡皮筋 + QRubberBand* _rubberBand = nullptr; // 原生橡皮筋 QList _selectionRectItems; - QwtPlotCurve* _fittedCurve = nullptr; // 显示拟合结果的曲线 + QwtPlotCurve* _fittedCurve = nullptr; // 显示拟合结果的曲线 // 存储当前显示的拟合曲线,用于清除 QList _fitCurves; - - QString _historyFilePath; // [NEW] 最近一次拟合结果(用于手动保存) PeakFitResult _lastFitResult; - arma::vec _lastFitParams; // 6个拟合参数 (A, delt, H, W, C, P) + arma::vec _lastFitParams; // 6个拟合参数 (A, delt, H, W, C, P) double _lastXMin = 0.0, _lastXMax = 0.0; bool _hasLastFit = false; QString _workspace; - //存储当前所有拟合结果(用于多曲线管理) + // 存储当前所有拟合结果(用于多曲线管理) QList _currentFitRecords; - //历史记录列表 + // 历史记录列表 QList _fitHistoryList; - //当前悬停的框选区域 + // 当前悬停的框选区域 PlotRectItem* _hoveredRectItem = nullptr; QList _displayedHistoryCurves; - }; #endif // ENERGYCOUNTPEAKFITVIEW_H diff --git a/src/ParticleInjectTimeView/ParticleInjectTimeAnalysisView.cpp b/src/ParticleInjectTimeView/ParticleInjectTimeAnalysisView.cpp index 7b47a42..e32e31e 100644 --- a/src/ParticleInjectTimeView/ParticleInjectTimeAnalysisView.cpp +++ b/src/ParticleInjectTimeView/ParticleInjectTimeAnalysisView.cpp @@ -106,9 +106,9 @@ void ParticleInjectTimeAnalysisView::setupMenu() void ParticleInjectTimeAnalysisView::updateData(bool b_init_update) { + _busy_indicator->Start(); auto functionToRun = [this, b_init_update](){ if(!_data_filename.isEmpty()) { - _busy_indicator->Start(); std::string board_id_str = QString(QStringLiteral(u"板卡号")).toStdString(); std::string channel_id_str = QString(QStringLiteral(u"通道号")).toStdString(); std::string energy_str = QString(QStringLiteral(u"能量(KeV)")).toStdString(); @@ -137,12 +137,14 @@ void ParticleInjectTimeAnalysisView::updateData(bool b_init_update) if ( y_max < time_count ) y_max = time_count; } - _plot->SetAxisInitRange(QwtPlot::xBottom, 0.0f, x_max); - _plot->SetAxisInitRange(QwtPlot::yLeft, 0.0f, y_max); - _curve->setSamples(x, y); - _plot->replot(); - LOG_INFO(QStringLiteral(u"%1数据更新完毕.").arg(this->GetViewName())); - _busy_indicator->Stop(); + QMetaObject::invokeMethod(this, [this, x_max, y_max, x, y]() { + _plot->SetAxisInitRange(QwtPlot::xBottom, 0.0f, x_max); + _plot->SetAxisInitRange(QwtPlot::yLeft, 0.0f, y_max); + _curve->setSamples(x, y); + _plot->replot(); + LOG_INFO(QStringLiteral(u"%1数据更新完毕.").arg(this->GetViewName())); + _busy_indicator->Stop(); + }, Qt::QueuedConnection); } }; QThread* load_data_thread = QThread::create(functionToRun); diff --git a/src/ParticleTimeDifferenceView/ParticleTimeDifferenceView.cpp b/src/ParticleTimeDifferenceView/ParticleTimeDifferenceView.cpp index 519709e..3c259c5 100644 --- a/src/ParticleTimeDifferenceView/ParticleTimeDifferenceView.cpp +++ b/src/ParticleTimeDifferenceView/ParticleTimeDifferenceView.cpp @@ -156,17 +156,21 @@ void ParticleTimeDifferenceView::loadDataFromFile() if ( y_max < count ) y_max = count; } - _histogram->setData(new QwtIntervalSeriesData(samples)); - _plot->SetAxisInitRange(QwtPlot::xBottom, 0.0f, x_max); - _plot->SetAxisInitRange(QwtPlot::yLeft, 0.0f, y_max); - _plot->replot(); - const QString& info = QStringLiteral(u"粒子时间差分析处理完成."); - LOG_INFO(info); + QMetaObject::invokeMethod(this, [this, samples, x_max, y_max]() { + _histogram->setData(new QwtIntervalSeriesData(samples)); + _plot->SetAxisInitRange(QwtPlot::xBottom, 0.0f, x_max); + _plot->SetAxisInitRange(QwtPlot::yLeft, 0.0f, y_max); + _plot->replot(); + const QString& info = QStringLiteral(u"粒子时间差分析处理完成."); + LOG_INFO(info); + }, Qt::QueuedConnection); } catch (const std::exception& e) { const QString& e_what = QString::fromStdString(e.what()); LOG_WARN(QStringLiteral(u"粒子时间差分析处理异常:%1").arg(e_what)); } - _busy_indicator->Stop(); + QMetaObject::invokeMethod(this, [this]() { + _busy_indicator->Stop(); + }, Qt::QueuedConnection); } void ParticleTimeDifferenceView::onActionPlotConfigure()