优化加载动画

This commit is contained in:
徐海 2026-05-13 11:29:36 +08:00
parent d0be9a8654
commit 814b85d40b
8 changed files with 122 additions and 109 deletions

View File

@ -68,12 +68,14 @@ void TwoDSpectralCompliance::SetAnalyzeDataFilename(const QMap<QString, QVariant
QString csvFile = data_files_set.first().toString();
if (csvFile.isEmpty())
return;
_busy_indicator->Start();
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();

View File

@ -83,11 +83,14 @@ void AntiConformEnergySpectrumView::SetAnalyzeDataFilename(const QMap<QString, Q
void AntiConformEnergySpectrumView::loadAndProcess()
{
_busy_indicator->Start();
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<SpectrumData> 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;
}

View File

@ -89,13 +89,15 @@ void CoincidenceEventTimeView::SetAnalyzeDataFilename(const QMap<QString, QVaria
void CoincidenceEventTimeView::loadAndProcess()
{
_busy_indicator->Start();
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<SpectrumData> 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<SpectrumData> 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<double> 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;
}

View File

@ -44,14 +44,14 @@ void CountRateAnalysisView::InitViewWorkspace(const QString &project_name)
}
void CountRateAnalysisView::SetAnalyzeDataFilename(const QMap<QString, QVariant> &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<ParticleInjectTime> 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();

View File

@ -44,7 +44,6 @@ private:
BusyIndicator* _busy_indicator = nullptr;
CustomQwtPlot *plot;
QMenu* _menu = nullptr;
QVector<ParticleInjectTime> m_AllData;//存储的所有的粒子入射时间数据
};
#endif //COUNTRATEANALYSIS_H

View File

@ -1,74 +1,76 @@
#ifndef ENERGYCOUNTPEAKFITVIEW_H
#define ENERGYCOUNTPEAKFITVIEW_H
#include <QObject>
#include <QWidget>
#include "PeakFitParamsDialog.h"
#include <MeasureAnalysisView.h>
#include <QwtPlotPicker>
#include <QwtPickerDragRectMachine>
#include <QRubberBand> // 新增
#include <qwt_plot_shapeitem.h> // 新增
#include <QDateTime>
#include <QJsonArray>
#include <QJsonObject>
#include "PeakFitParamsDialog.h"
#include <QObject>
#include <QRubberBand> // 新增
#include <QWidget>
#include <QwtPickerDragRectMachine>
#include <QwtPlotPicker>
#include <qwt_plot_shapeitem.h> // 新增
#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<FitCurveData> curveList; //存储多条曲线
QList<FitCurveData> 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<FitCurveData>& curves, const QList<DisplayedCurveRef>& 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<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*/);
// 根据拟合参数生成曲线
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<PlotRectItem*> _selectionRectItems;
QwtPlotCurve* _fittedCurve = nullptr; // 显示拟合结果的曲线
QwtPlotCurve* _fittedCurve = nullptr; // 显示拟合结果的曲线
// 存储当前显示的拟合曲线,用于清除
QList<QwtPlotCurve*> _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<CurrentFitRecord> _currentFitRecords;
//历史记录列表
// 历史记录列表
QList<PeakFitHistoryItem> _fitHistoryList;
//当前悬停的框选区域
// 当前悬停的框选区域
PlotRectItem* _hoveredRectItem = nullptr;
QList<DisplayedCurveRef> _displayedHistoryCurves;
};
#endif // ENERGYCOUNTPEAKFITVIEW_H

View File

@ -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);

View File

@ -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()