优化加载动画
This commit is contained in:
parent
d0be9a8654
commit
814b85d40b
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ private:
|
|||
BusyIndicator* _busy_indicator = nullptr;
|
||||
CustomQwtPlot *plot;
|
||||
QMenu* _menu = nullptr;
|
||||
QVector<ParticleInjectTime> m_AllData;//存储的所有的粒子入射时间数据
|
||||
};
|
||||
|
||||
#endif //COUNTRATEANALYSIS_H
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user