修改读取数据为线程处理,新增核素分析操作列,新增核素分析保存和新增按钮
This commit is contained in:
parent
1c7784702f
commit
1c6bd01ed6
|
|
@ -23,7 +23,6 @@
|
|||
#include "EnergyScaleDataModel.h"
|
||||
#include "DataCalcProcess/CoincidenceSpectrumProcess.h"
|
||||
#include "BackgroundTaskListModel.h"
|
||||
#include "GvfToCsv/GvfToCsv.h"
|
||||
#include <QDebug>
|
||||
|
||||
using namespace DataProcessWorkPool;
|
||||
|
|
@ -1132,4 +1131,352 @@ bool GvfToCsvDataTask::processTask()
|
|||
}
|
||||
|
||||
return m_conversionSuccess;
|
||||
}
|
||||
|
||||
//2026-06-24
|
||||
RealtimeGvfDataWorker::RealtimeGvfDataWorker(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
RealtimeGvfDataWorker::~RealtimeGvfDataWorker()
|
||||
{
|
||||
}
|
||||
|
||||
void RealtimeGvfDataWorker::setGvfParser(GvfToCsv *parser)
|
||||
{
|
||||
_gvfToCsv = parser;
|
||||
}
|
||||
|
||||
void RealtimeGvfDataWorker::syncInitialData(
|
||||
const QHash<uint, std::array<unsigned long long, 4096>> &addrCounts,
|
||||
const QHash<uint, QHash<double, unsigned long long>> &energyCounts,
|
||||
const QHash<double, unsigned long long> &allChannelEnergyCounts,
|
||||
const QHash<uint, QString> &addrCountFilenames,
|
||||
const QHash<uint, QString> &energyCountFilenames)
|
||||
{
|
||||
QMutexLocker locker1(&m_channelCountMutex);
|
||||
QMutexLocker locker2(&m_energyCountMutex);
|
||||
channel_address_counts = addrCounts;
|
||||
channel_energy_counts = energyCounts;
|
||||
all_channel_energy_counts = allChannelEnergyCounts;
|
||||
particle_count_filename_list = addrCountFilenames;
|
||||
energy_count_filename_list = energyCountFilenames;
|
||||
}
|
||||
|
||||
void RealtimeGvfDataWorker::processGvfData(const QByteArray &data,
|
||||
const QString &projectDir,
|
||||
const QString &energyScaleFilename,
|
||||
const QString &projectName)
|
||||
{
|
||||
if (!_gvfToCsv) return;
|
||||
|
||||
QList<ParticleData> particles = _gvfToCsv->parseParticleFrames(data);
|
||||
if (particles.isEmpty()) {
|
||||
LOG_INFO(QStringLiteral(u"[%1]本次GVF数据未解析到有效粒子,跳过处理").arg(projectName));
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. 粒子数据写入CSV
|
||||
changeParticleData(particles, projectDir);
|
||||
emit particleDataWritten();
|
||||
|
||||
// 2. 道址计数统计
|
||||
changeChannelParticleCount(particles, projectDir);
|
||||
emit addressCountUpdated();
|
||||
emit addressCountViewNeedRefresh();
|
||||
|
||||
// 3. 粒子能量数据(需能量刻度)
|
||||
if (!energyScaleFilename.isEmpty()) {
|
||||
changeParticleEnergyData(particles, projectDir, energyScaleFilename, projectName);
|
||||
}
|
||||
|
||||
// 4. 能量计数统计(需能量刻度)
|
||||
if (!energyScaleFilename.isEmpty()) {
|
||||
changeEnergyCountData(particles, projectDir, energyScaleFilename, projectName);
|
||||
emit energyCountUpdated();
|
||||
emit energyCountViewNeedRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 粒子数据写入CSV ----
|
||||
void RealtimeGvfDataWorker::changeParticleData(QList<ParticleData> &dataList, const QString &projectDir)
|
||||
{
|
||||
QString csvPath = QDir(projectDir).filePath(QStringLiteral(u"粒子数据.csv"));
|
||||
QFile outFile(csvPath);
|
||||
if (!outFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) {
|
||||
LOG_ERROR(QStringLiteral(u"无法打开CSV文件(追加模式): %1,错误: %2")
|
||||
.arg(csvPath).arg(outFile.errorString()));
|
||||
return;
|
||||
}
|
||||
|
||||
QTextStream out(&outFile);
|
||||
out.setCodec("UTF-8");
|
||||
if (outFile.size() == 0) {
|
||||
out << QStringLiteral(u"板卡号,通道号,道址,时间计数\n");
|
||||
}
|
||||
|
||||
QString csvBuffer;
|
||||
csvBuffer.reserve(dataList.size() * 64);
|
||||
for (const auto &p : dataList) {
|
||||
csvBuffer += QString("%1,%2,%3,%4\n")
|
||||
.arg(p.boardId).arg(p.channelId)
|
||||
.arg(p.address).arg(p.timestampCount);
|
||||
}
|
||||
out << csvBuffer;
|
||||
out.flush();
|
||||
outFile.close();
|
||||
}
|
||||
|
||||
// ---- 道址计数统计 ----
|
||||
void RealtimeGvfDataWorker::changeChannelParticleCount(QList<ParticleData> &data, const QString &projectDir)
|
||||
{
|
||||
QHash<uint, QHash<uint, unsigned long long>> deltaCounts;
|
||||
for (const auto &info : data) {
|
||||
int channel_num = info.boardId * 4 + info.channelId + 1;
|
||||
uint address = info.address;
|
||||
if (address >= 4096) continue;
|
||||
deltaCounts[channel_num][address]++;
|
||||
}
|
||||
if (deltaCounts.isEmpty()) return;
|
||||
|
||||
const QString every_ch_count_dir = QDir(projectDir).filePath(QStringLiteral(u"通道道址计数"));
|
||||
QDir(every_ch_count_dir).mkpath(every_ch_count_dir);
|
||||
|
||||
QMutexLocker locker(&m_channelCountMutex);
|
||||
bool hasError = false;
|
||||
QHash<uint, QString> newChannelFiles;
|
||||
for (auto channelIt = deltaCounts.constBegin(); channelIt != deltaCounts.constEnd(); ++channelIt) {
|
||||
uint channel_num = channelIt.key();
|
||||
const auto &addressDeltas = channelIt.value();
|
||||
|
||||
if (!channel_address_counts.contains(channel_num)) {
|
||||
std::array<unsigned long long, 4096> init;
|
||||
init.fill(0);
|
||||
channel_address_counts.insert(channel_num, init);
|
||||
}
|
||||
|
||||
auto &channelCounts = channel_address_counts[channel_num];
|
||||
for (auto addrIt = addressDeltas.constBegin(); addrIt != addressDeltas.constEnd(); ++addrIt) {
|
||||
channelCounts[addrIt.key()] += addrIt.value();
|
||||
}
|
||||
|
||||
QString count_data_filename;
|
||||
if (particle_count_filename_list.contains(channel_num)) {
|
||||
count_data_filename = particle_count_filename_list[channel_num];
|
||||
} else {
|
||||
count_data_filename = QDir(every_ch_count_dir).filePath(
|
||||
QStringLiteral(u"通道%1粒子计数.csv").arg(channel_num));
|
||||
particle_count_filename_list.insert(channel_num, count_data_filename);
|
||||
newChannelFiles.insert(channel_num, count_data_filename); // 新增的加入记录
|
||||
}
|
||||
QString tmp_filename = count_data_filename + ".tmp";
|
||||
QFile outFile(tmp_filename);
|
||||
if (!outFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
|
||||
hasError = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
QTextStream out(&outFile);
|
||||
out.setCodec("UTF-8");
|
||||
out << QStringLiteral(u"道址,计数\n");
|
||||
|
||||
QString csvBuffer;
|
||||
csvBuffer.reserve(4096 * 32);
|
||||
for (int address = 0; address < 4096; ++address) {
|
||||
csvBuffer += QString("%1,%2\n").arg(address).arg(channelCounts[address]);
|
||||
}
|
||||
out << csvBuffer;
|
||||
out.flush();
|
||||
outFile.close();
|
||||
|
||||
// 写完后原子替换原文件
|
||||
QFile::remove(count_data_filename);
|
||||
QFile::rename(tmp_filename, count_data_filename);
|
||||
}
|
||||
// 只通知新增的通道文件
|
||||
for (auto it = newChannelFiles.constBegin(); it != newChannelFiles.constEnd(); ++it) {
|
||||
emit newAddressCountChannelFile(it.key(), it.value());
|
||||
}
|
||||
if (hasError) {
|
||||
LOG_WARN(QStringLiteral(u"部分通道的道址计数数据写入失败"));
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 粒子能量数据 ----
|
||||
void RealtimeGvfDataWorker::changeParticleEnergyData(QList<ParticleData> &dataList,
|
||||
const QString &projectDir,
|
||||
const QString &energyScaleFilename,
|
||||
const QString &projectName)
|
||||
{
|
||||
EnergyScaleDataModel energy_scale_data_model(energyScaleFilename);
|
||||
if (!energy_scale_data_model.LoadData() || !energy_scale_data_model.IsValid()) {
|
||||
LOG_WARN(QStringLiteral(u"[%1]能量刻度数据无效,跳过能谱处理").arg(projectName));
|
||||
return;
|
||||
}
|
||||
|
||||
QMutexLocker locker(&m_energyDataMutex);
|
||||
QString energy_spectrum_filename = QDir(projectDir).filePath(QStringLiteral(u"能谱数据.csv"));
|
||||
QFile outFile(energy_spectrum_filename);
|
||||
if (!outFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) {
|
||||
LOG_ERROR(QStringLiteral(u"[%1]无法打开能谱文件: %2").arg(projectName).arg(energy_spectrum_filename));
|
||||
return;
|
||||
}
|
||||
|
||||
QTextStream out(&outFile);
|
||||
out.setCodec("UTF-8");
|
||||
if (outFile.size() == 0) {
|
||||
out << QStringLiteral(u"板卡号,通道号,道址,能量(KeV),时间计数\n");
|
||||
}
|
||||
|
||||
QString csvBuffer;
|
||||
csvBuffer.reserve(dataList.size() * 80);
|
||||
|
||||
for (const auto &particle : dataList) {
|
||||
int channel_num = particle.boardId * 4 + particle.channelId + 1;
|
||||
const QString channel_name = QStringLiteral(u"通道%1").arg(channel_num);
|
||||
std::vector<double> coeffs = energy_scale_data_model.GetEnergyFitResultCoeffs(channel_name);
|
||||
if (coeffs.empty()) continue;
|
||||
|
||||
double energy = GaussPolyCoe::Predict(coeffs, particle.address);
|
||||
csvBuffer += QString("%1,%2,%3,%4,%5\n")
|
||||
.arg(particle.boardId).arg(particle.channelId)
|
||||
.arg(particle.address)
|
||||
.arg(energy, 0, 'f', 4)
|
||||
.arg(particle.timestampCount);
|
||||
}
|
||||
|
||||
if (!csvBuffer.isEmpty()) {
|
||||
out << csvBuffer;
|
||||
out.flush();
|
||||
}
|
||||
outFile.close();
|
||||
if (!csvBuffer.isEmpty())
|
||||
emit particleEnergyDataUpdated(energy_spectrum_filename);
|
||||
|
||||
}
|
||||
|
||||
// ---- 能量计数统计 ----
|
||||
void RealtimeGvfDataWorker::changeEnergyCountData(QList<ParticleData> &dataList,
|
||||
const QString &projectDir,
|
||||
const QString &energyScaleFilename,
|
||||
const QString &projectName)
|
||||
{
|
||||
EnergyScaleDataModel energy_scale_data_model(energyScaleFilename);
|
||||
if (!energy_scale_data_model.LoadData() || !energy_scale_data_model.IsValid()) {
|
||||
LOG_WARN(QStringLiteral(u"[%1]能量刻度数据无效,跳过能量计数处理").arg(projectName));
|
||||
return;
|
||||
}
|
||||
|
||||
QHash<uint, QHash<double, unsigned long long>> deltaCounts;
|
||||
QHash<double, unsigned long long> deltaAllChannelCounts;
|
||||
|
||||
for (const auto &particle : dataList) {
|
||||
int channel_num = particle.boardId * 4 + particle.channelId + 1;
|
||||
const QString channel_name = QStringLiteral(u"通道%1").arg(channel_num);
|
||||
std::vector<double> coeffs = energy_scale_data_model.GetEnergyFitResultCoeffs(channel_name);
|
||||
if (coeffs.empty()) continue;
|
||||
|
||||
double energy = GaussPolyCoe::Predict(coeffs, particle.address);
|
||||
double energy_key = qRound(energy * 10.0) / 10.0;
|
||||
deltaCounts[channel_num][energy_key]++;
|
||||
deltaAllChannelCounts[energy_key]++;
|
||||
}
|
||||
|
||||
if (deltaCounts.isEmpty()) return;
|
||||
|
||||
const QString energy_count_dir = QDir(projectDir).filePath(QStringLiteral(u"通道能量计数"));
|
||||
QDir(energy_count_dir).mkpath(energy_count_dir);
|
||||
|
||||
QMutexLocker locker(&m_energyCountMutex);
|
||||
bool hasError = false;
|
||||
QHash<uint, QString> newChannelFiles;
|
||||
for (auto channelIt = deltaCounts.constBegin(); channelIt != deltaCounts.constEnd(); ++channelIt) {
|
||||
uint channel_num = channelIt.key();
|
||||
const auto &energyDeltas = channelIt.value();
|
||||
auto &channelCounts = channel_energy_counts[channel_num];
|
||||
|
||||
for (auto eIt = energyDeltas.constBegin(); eIt != energyDeltas.constEnd(); ++eIt) {
|
||||
channelCounts[eIt.key()] += eIt.value();
|
||||
}
|
||||
|
||||
QString count_data_filename;
|
||||
if (energy_count_filename_list.contains(channel_num)) {
|
||||
count_data_filename = energy_count_filename_list[channel_num];
|
||||
} else {
|
||||
count_data_filename = QDir(energy_count_dir).filePath(
|
||||
QStringLiteral(u"通道%1能量计数.csv").arg(channel_num));
|
||||
energy_count_filename_list.insert(channel_num, count_data_filename);
|
||||
newChannelFiles.insert(channel_num, count_data_filename);
|
||||
}
|
||||
QString tmp_filename = count_data_filename + ".tmp";
|
||||
QFile outFile(tmp_filename);
|
||||
if (!outFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
|
||||
hasError = true;
|
||||
continue;
|
||||
}
|
||||
QTextStream out(&outFile);
|
||||
out.setCodec("UTF-8");
|
||||
out << QStringLiteral(u"能量(KeV),计数\n");
|
||||
|
||||
QList<double> sortedEnergies = channelCounts.keys();
|
||||
std::sort(sortedEnergies.begin(), sortedEnergies.end());
|
||||
|
||||
QString csvBuffer;
|
||||
csvBuffer.reserve(sortedEnergies.size() * 40);
|
||||
for (double energy : sortedEnergies) {
|
||||
csvBuffer += QString("%1,%2\n").arg(energy, 0, 'f', 1).arg(channelCounts[energy]);
|
||||
}
|
||||
out << csvBuffer;
|
||||
out.flush();
|
||||
outFile.close();
|
||||
// 原子替换
|
||||
QFile::remove(count_data_filename);
|
||||
QFile::rename(tmp_filename, count_data_filename);
|
||||
}
|
||||
|
||||
// 全通道能量计数
|
||||
if (!deltaAllChannelCounts.isEmpty()) {
|
||||
for (auto eIt = deltaAllChannelCounts.constBegin(); eIt != deltaAllChannelCounts.constEnd(); ++eIt) {
|
||||
all_channel_energy_counts[eIt.key()] += eIt.value();
|
||||
}
|
||||
QString all_ch_filename = QDir(energy_count_dir).filePath(QStringLiteral(u"全通道.csv"));
|
||||
QString tmp_filename = all_ch_filename + ".tmp";
|
||||
|
||||
QFile allChannelFile(tmp_filename);
|
||||
if (allChannelFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
|
||||
QTextStream outAll(&allChannelFile);
|
||||
outAll.setCodec("UTF-8");
|
||||
outAll << QStringLiteral(u"能量(KeV),计数\n");
|
||||
|
||||
QList<double> sortedAll = all_channel_energy_counts.keys();
|
||||
std::sort(sortedAll.begin(), sortedAll.end());
|
||||
|
||||
QString allCsvBuffer;
|
||||
allCsvBuffer.reserve(sortedAll.size() * 40);
|
||||
for (double e : sortedAll) {
|
||||
allCsvBuffer += QString("%1,%2\n").arg(e, 0, 'f', 3).arg(all_channel_energy_counts[e]);
|
||||
}
|
||||
outAll << allCsvBuffer;
|
||||
outAll.flush();
|
||||
allChannelFile.close();
|
||||
QFile::remove(all_ch_filename);
|
||||
QFile::rename(tmp_filename, all_ch_filename);
|
||||
} else {
|
||||
hasError = true;
|
||||
}
|
||||
}
|
||||
// 通知主线程:新通道文件已生成,更新项目模型
|
||||
for (auto it = newChannelFiles.constBegin(); it != newChannelFiles.constEnd(); ++it) {
|
||||
emit newEnergyCountChannelFile(it.key(), it.value());
|
||||
}
|
||||
|
||||
// 通知主线程:全通道能量计数文件更新
|
||||
QString all_ch_filename = QDir(energy_count_dir).filePath(QStringLiteral(u"全通道.csv"));
|
||||
if (!deltaAllChannelCounts.isEmpty()) {
|
||||
emit allChannelEnergyCountFileUpdated(all_ch_filename);
|
||||
}
|
||||
if (hasError) {
|
||||
LOG_WARN(QStringLiteral(u"部分通道的能量计数数据写入失败"));
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,9 @@
|
|||
#include <QMap>
|
||||
#include <QVariant>
|
||||
#include <QEventLoop>
|
||||
#include <array>
|
||||
#include "GvfToCsv/GvfToCsv.h"
|
||||
|
||||
class EnergyScaleDataModel;
|
||||
class MeasureAnalysisProjectModel;
|
||||
|
||||
|
|
@ -184,6 +187,71 @@ namespace DataProcessWorkPool
|
|||
QString m_error;
|
||||
bool m_conversionSuccess = false;
|
||||
};
|
||||
|
||||
class RealtimeGvfDataWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RealtimeGvfDataWorker(QObject *parent = nullptr);
|
||||
~RealtimeGvfDataWorker();
|
||||
|
||||
// 设置GVF解析器
|
||||
void setGvfParser(GvfToCsv *parser);
|
||||
|
||||
// 同步初始计数数据(开始测量前调用一次)
|
||||
void syncInitialData(
|
||||
const QHash<uint, std::array<unsigned long long, 4096>> &addrCounts,
|
||||
const QHash<uint, QHash<double, unsigned long long>> &energyCounts,
|
||||
const QHash<double, unsigned long long> &allChannelEnergyCounts,
|
||||
const QHash<uint, QString> &addrCountFilenames,
|
||||
const QHash<uint, QString> &energyCountFilenames);
|
||||
|
||||
signals:
|
||||
// 处理完成信号(回到主线程更新UI)
|
||||
void particleDataWritten(); // 粒子数据CSV写入完成
|
||||
void addressCountUpdated(); // 道址计数更新完成
|
||||
void energyCountUpdated(); // 能量计数更新完成
|
||||
void addressCountViewNeedRefresh(); // 需要刷新道址计数谱
|
||||
void energyCountViewNeedRefresh(); // 需要刷新能量计数谱
|
||||
// 道址计数有新通道文件生成(通知主线程更新项目模型和节点)
|
||||
void newAddressCountChannelFile(uint channelNum, const QString &filename);
|
||||
// 能量计数有新通道文件生成
|
||||
void newEnergyCountChannelFile(uint channelNum, const QString &filename);
|
||||
// 全通道能量计数文件更新
|
||||
void allChannelEnergyCountFileUpdated(const QString &filename);
|
||||
// 粒子能量数据写入完成(通知主线程更新节点状态)
|
||||
void particleEnergyDataUpdated(const QString &energySpectrumFilename);
|
||||
public slots:
|
||||
// 处理一批GVF数据(在子线程中执行)
|
||||
void processGvfData(const QByteArray &data,
|
||||
const QString &projectDir,
|
||||
const QString &energyScaleFilename,
|
||||
const QString &projectName);
|
||||
|
||||
private:
|
||||
void changeParticleData(QList<ParticleData> &dataList, const QString &projectDir);
|
||||
void changeChannelParticleCount(QList<ParticleData> &data, const QString &projectDir);
|
||||
void changeParticleEnergyData(QList<ParticleData> &dataList, const QString &projectDir,
|
||||
const QString &energyScaleFilename, const QString &projectName);
|
||||
void changeEnergyCountData(QList<ParticleData> &dataList, const QString &projectDir,
|
||||
const QString &energyScaleFilename, const QString &projectName);
|
||||
|
||||
GvfToCsv *_gvfToCsv = nullptr;
|
||||
|
||||
// 通道道址计数缓存
|
||||
QHash<uint, std::array<unsigned long long, 4096>> channel_address_counts;
|
||||
// 通道能量计数缓存
|
||||
QHash<uint, QHash<double, unsigned long long>> channel_energy_counts;
|
||||
// 全通道能量计数缓存
|
||||
QHash<double, unsigned long long> all_channel_energy_counts;
|
||||
// 文件路径缓存
|
||||
QHash<uint, QString> particle_count_filename_list;
|
||||
QHash<uint, QString> energy_count_filename_list;
|
||||
|
||||
QMutex m_channelCountMutex;
|
||||
QMutex m_energyDataMutex;
|
||||
QMutex m_energyCountMutex;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // DATAPROCESSWORKPOOL_H
|
||||
|
|
|
|||
|
|
@ -50,6 +50,10 @@ void EnergyCountPlotView::SetAnalyzeDataFilename(const QMap<QString, QVariant> &
|
|||
for (const QString& ch_count_data_name : ch_count_data_name) {
|
||||
if (ch_count_data_name.contains(ch_count_data_name)) {
|
||||
const QString ch_count_data_filename = data_files_set[ch_count_data_name].toString();
|
||||
QFileInfo fileInfo(ch_count_data_filename);
|
||||
if (!fileInfo.exists() || fileInfo.size() == 0) {
|
||||
continue; // 文件不存在或为空,跳过
|
||||
}
|
||||
loadDataFromFile(ch_count_data_name, ch_count_data_filename);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -124,6 +124,29 @@ MainWindow::MainWindow(QWidget* parent)
|
|||
initAction();
|
||||
initStatusBar();
|
||||
|
||||
// 初始化实时GVF数据处理线程
|
||||
_gvfProcessThread = new QThread(this);
|
||||
_gvfWorker = new DataProcessWorkPool::RealtimeGvfDataWorker;
|
||||
_gvfWorker->setGvfParser(_gvfToCsv);
|
||||
_gvfWorker->moveToThread(_gvfProcessThread);
|
||||
|
||||
// 连接UI更新信号
|
||||
connect(_gvfWorker, &DataProcessWorkPool::RealtimeGvfDataWorker::particleDataWritten,
|
||||
this, &MainWindow::updataTable);
|
||||
connect(_gvfWorker, &DataProcessWorkPool::RealtimeGvfDataWorker::addressCountViewNeedRefresh,
|
||||
this, &MainWindow::onAddressCountViewNeedRefresh);
|
||||
connect(_gvfWorker, &DataProcessWorkPool::RealtimeGvfDataWorker::energyCountViewNeedRefresh,
|
||||
this, &MainWindow::onEnergyCountViewNeedRefresh);
|
||||
connect(_gvfWorker, &DataProcessWorkPool::RealtimeGvfDataWorker::newAddressCountChannelFile,
|
||||
this, &MainWindow::onNewAddressCountChannelFile);
|
||||
connect(_gvfWorker, &DataProcessWorkPool::RealtimeGvfDataWorker::newEnergyCountChannelFile,
|
||||
this, &MainWindow::onNewEnergyCountChannelFile);
|
||||
connect(_gvfWorker, &DataProcessWorkPool::RealtimeGvfDataWorker::allChannelEnergyCountFileUpdated,
|
||||
this, &MainWindow::onAllChannelEnergyCountFileUpdated);
|
||||
connect(_gvfWorker, &DataProcessWorkPool::RealtimeGvfDataWorker::particleEnergyDataUpdated,
|
||||
this, &MainWindow::onParticleEnergyDataUpdated);
|
||||
_gvfProcessThread->start();
|
||||
|
||||
this->applyStyleSheet();
|
||||
_s_main_win = this;
|
||||
}
|
||||
|
|
@ -612,19 +635,27 @@ void MainWindow::onRunningInfo(const QString &run_info)
|
|||
|
||||
void MainWindow::onGvfData(const QByteArray &data)
|
||||
{
|
||||
QList<ParticleData> particles = _gvfToCsv->parseParticleFrames(data);
|
||||
//处理粒子数据
|
||||
changeParticleData(particles);
|
||||
//处理道址计数
|
||||
changeChannelParticleCount(particles);
|
||||
//处理能谱数据
|
||||
changeParticleEnergyData(particles);
|
||||
//处理能量计数
|
||||
changeEnergyCountData(particles);
|
||||
//处理道址计数谱
|
||||
changeAddressCountView(particles);
|
||||
//处理能量计数谱
|
||||
changeEnergyCountView(particles);
|
||||
// QList<ParticleData> particles = _gvfToCsv->parseParticleFrames(data);
|
||||
// //处理粒子数据
|
||||
// changeParticleData(particles);
|
||||
// //处理道址计数
|
||||
// changeChannelParticleCount(particles);
|
||||
// //处理能谱数据
|
||||
// changeParticleEnergyData(particles);
|
||||
// //处理能量计数
|
||||
// changeEnergyCountData(particles);
|
||||
// //处理道址计数谱
|
||||
// changeAddressCountView(particles);
|
||||
// //处理能量计数谱
|
||||
// changeEnergyCountView(particles);
|
||||
MeasureAnalysisProjectModel *project_model = ProjectList::Instance()->GetCurrentProjectModel();
|
||||
if (!project_model) return;
|
||||
|
||||
QMetaObject::invokeMethod(_gvfWorker, "processGvfData", Qt::QueuedConnection,
|
||||
Q_ARG(QByteArray, data),
|
||||
Q_ARG(QString, project_model->GetProjectDir()),
|
||||
Q_ARG(QString, project_model->GetEnergyScaleFilename()),
|
||||
Q_ARG(QString, project_model->GetProjectName()));
|
||||
}
|
||||
|
||||
//处理粒子数据
|
||||
|
|
@ -1292,3 +1323,128 @@ void MainWindow::on_action_device_connect_cfg_triggered()
|
|||
|
||||
}
|
||||
|
||||
void MainWindow::onAddressCountViewNeedRefresh()
|
||||
{
|
||||
MeasureAnalysisProjectModel *pro_model = ProjectList::Instance()->GetCurrentProjectModel();
|
||||
if (!pro_model) return;
|
||||
|
||||
bool status_ok = !pro_model->GetChannelAddressCountDataFilenameList().isEmpty();
|
||||
QString status = status_ok ? QStringLiteral(u"有效") : QStringLiteral(u"无效");
|
||||
QString item_name = QStringLiteral(u"道址计数谱");
|
||||
QStandardItem *particleData = nodeMap[item_name];
|
||||
|
||||
if (particleData) {
|
||||
bool bStatus = ProjectList::Instance()->GetNodeStatus(particleData);
|
||||
if (!bStatus) {
|
||||
ProjectList::Instance()->SetNodeStatus(particleData, status, true);
|
||||
m_AddressCountTimer->start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onEnergyCountViewNeedRefresh()
|
||||
{
|
||||
MeasureAnalysisProjectModel *pro_model = ProjectList::Instance()->GetCurrentProjectModel();
|
||||
if (!pro_model) return;
|
||||
|
||||
bool status_ok = !pro_model->GetChannelEnergyCountDataFilenameList().isEmpty();
|
||||
QString status = status_ok ? QStringLiteral(u"有效") : QStringLiteral(u"无效");
|
||||
QString item_name = QStringLiteral(u"能量计数谱");
|
||||
QStandardItem *particleData = nodeMap[item_name];
|
||||
|
||||
if (particleData) {
|
||||
bool bStatus = ProjectList::Instance()->GetNodeStatus(particleData);
|
||||
if (!bStatus) {
|
||||
ProjectList::Instance()->SetNodeStatus(particleData, status, true);
|
||||
m_EnergyCountTimer->start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onNewAddressCountChannelFile(uint channelNum, const QString &filename)
|
||||
{
|
||||
MeasureAnalysisProjectModel *project_model = ProjectList::Instance()->GetCurrentProjectModel();
|
||||
if (!project_model) return;
|
||||
|
||||
project_model->SetChannelAddressCountDataFilename(channelNum, filename);
|
||||
project_model->SaveProjectModel();
|
||||
|
||||
// 更新项目树节点
|
||||
const QString &adrr_count_item_name = QStringLiteral(u"道址计数");
|
||||
if (nodeMap.contains(adrr_count_item_name)) {
|
||||
QStandardItem *adrr_count_item = nodeMap[adrr_count_item_name];
|
||||
bool status_ok = !project_model->GetChannelAddressCountDataFilenameList().isEmpty();
|
||||
QString status = status_ok ? QStringLiteral(u"有效") : QStringLiteral(u"无效");
|
||||
ProjectList::Instance()->SetNodeStatus(adrr_count_item, status, status_ok);
|
||||
|
||||
QString item_name = QStringLiteral(u"通道%1道址计数").arg(channelNum);
|
||||
if (!nodeMap.contains(item_name)) {
|
||||
const QVariant &analys_type = QVariant::fromValue(AnalysisType::AddressCountData);
|
||||
QStandardItem *node_item = ProjectList::Instance()->AddChildNode(
|
||||
adrr_count_item, item_name, status, analys_type, true, status_ok);
|
||||
node_item->setData(project_model->GetProjectName(), Qt::UserRole + 2);
|
||||
node_item->setData(channelNum, Qt::UserRole + 3);
|
||||
nodeMap[item_name] = node_item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onNewEnergyCountChannelFile(uint channelNum, const QString &filename)
|
||||
{
|
||||
MeasureAnalysisProjectModel *project_model = ProjectList::Instance()->GetCurrentProjectModel();
|
||||
if (!project_model) return;
|
||||
|
||||
project_model->SetChannelEnergyCountDataFilename(channelNum, filename);
|
||||
project_model->SaveProjectModel();
|
||||
|
||||
// 更新项目树节点
|
||||
const QString &energy_count_item_name = QStringLiteral(u"能量计数");
|
||||
QMap<QString, QMap<QString, QStandardItem *>> all_nodes = ProjectList::Instance()->getProjectNodeItems();
|
||||
QMap<QString, QStandardItem *> project_nodes = all_nodes[project_model->GetProjectName()];
|
||||
|
||||
if (project_nodes.contains(energy_count_item_name)) {
|
||||
QStandardItem *energy_count_item = project_nodes[energy_count_item_name];
|
||||
bool status_ok = !project_model->GetChannelEnergyCountDataFilenameList().isEmpty();
|
||||
QString status = status_ok ? QStringLiteral(u"有效") : QStringLiteral(u"无效");
|
||||
ProjectList::Instance()->SetNodeStatus(energy_count_item, status, status_ok);
|
||||
|
||||
QString item_name = QStringLiteral(u"通道%1能量计数").arg(channelNum);
|
||||
if (!project_nodes.contains(item_name)) {
|
||||
const QVariant &analys_type = QVariant::fromValue(AnalysisType::EnergyCountData);
|
||||
QStandardItem *node_item = ProjectList::Instance()->AddChildNode(
|
||||
energy_count_item, item_name, status, analys_type, true, status_ok);
|
||||
node_item->setData(project_model->GetProjectName(), Qt::UserRole + 2);
|
||||
node_item->setData(channelNum, Qt::UserRole + 3);
|
||||
project_nodes[item_name] = node_item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onAllChannelEnergyCountFileUpdated(const QString &filename)
|
||||
{
|
||||
MeasureAnalysisProjectModel *project_model = ProjectList::Instance()->GetCurrentProjectModel();
|
||||
if (!project_model) return;
|
||||
|
||||
project_model->SetAllChannelEnergyTotalCountDataFilename(filename);
|
||||
project_model->SaveProjectModel();
|
||||
}
|
||||
|
||||
void MainWindow::onParticleEnergyDataUpdated(const QString &energySpectrumFilename)
|
||||
{
|
||||
MeasureAnalysisProjectModel *project_model = ProjectList::Instance()->GetCurrentProjectModel();
|
||||
if (!project_model) return;
|
||||
|
||||
// 更新项目模型
|
||||
project_model->SetParticleEnergyDataFilename(energySpectrumFilename);
|
||||
project_model->SaveProjectModel();
|
||||
|
||||
// 更新节点状态
|
||||
const QString &energy_node_name = QStringLiteral(u"粒子能量数据");
|
||||
if (nodeMap.contains(energy_node_name)) {
|
||||
QStandardItem *energy_node = nodeMap[energy_node_name];
|
||||
ProjectList::Instance()->SetNodeStatus(energy_node, QStringLiteral(u"有效"), true);
|
||||
}
|
||||
|
||||
// 更新数据表格
|
||||
// updataTable();
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
#include <QMutex>
|
||||
#include "GvfToCsv/GvfToCsv.h"
|
||||
#include "MeasureAnalysisProjectModel.h"
|
||||
#include "DataProcessWorkPool.h"
|
||||
#include <QTimer>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
|
@ -103,6 +104,13 @@ private slots:
|
|||
//设备连接管理
|
||||
void on_action_device_connect_cfg_triggered();
|
||||
|
||||
void onAddressCountViewNeedRefresh();
|
||||
void onEnergyCountViewNeedRefresh();
|
||||
void onNewAddressCountChannelFile(uint channelNum, const QString &filename);
|
||||
void onNewEnergyCountChannelFile(uint channelNum, const QString &filename);
|
||||
void onAllChannelEnergyCountFileUpdated(const QString &filename);
|
||||
void onParticleEnergyDataUpdated(const QString &energySpectrumFilename);
|
||||
|
||||
private:
|
||||
QMutex _mutex_info_output;
|
||||
QPlainTextEdit* _plain_edit_info_output;
|
||||
|
|
@ -143,5 +151,8 @@ private:
|
|||
//能量计数视图定时器
|
||||
QTimer* m_EnergyCountTimer;
|
||||
|
||||
QThread *_gvfProcessThread = nullptr;
|
||||
DataProcessWorkPool::RealtimeGvfDataWorker *_gvfWorker = nullptr;
|
||||
|
||||
};
|
||||
#endif // MAINWINDOW_H
|
||||
|
|
|
|||
|
|
@ -314,6 +314,7 @@ void NuclideAnalysisView::onActionPlotClear()
|
|||
_plot->replot();
|
||||
}
|
||||
|
||||
|
||||
void NuclideAnalysisView::addVerticalLine(double xValue, const QColor& color)
|
||||
{
|
||||
if(!m_bSelectHS)
|
||||
|
|
@ -637,6 +638,18 @@ void NuclideAnalysisView::setupNuclideDialog()
|
|||
QVBoxLayout* layout = new QVBoxLayout(m_nuclideDialog);
|
||||
layout->setContentsMargins(6, 6, 6, 6);
|
||||
|
||||
QHBoxLayout* topBarLayout = new QHBoxLayout();
|
||||
topBarLayout->addStretch();
|
||||
m_addBtn = new QPushButton(QStringLiteral(u"新增核素"), m_nuclideDialog);
|
||||
m_addBtn->setFixedWidth(80);
|
||||
connect(m_addBtn, &QPushButton::clicked, this, &NuclideAnalysisView::onAddNuclide);
|
||||
topBarLayout->addWidget(m_addBtn);
|
||||
m_saveBtn = new QPushButton(QStringLiteral(u"保存"), m_nuclideDialog);
|
||||
m_saveBtn->setFixedWidth(80);
|
||||
connect(m_saveBtn, &QPushButton::clicked, this, &NuclideAnalysisView::onSaveSelectedNuclides);
|
||||
topBarLayout->addWidget(m_saveBtn);
|
||||
layout->addLayout(topBarLayout);
|
||||
|
||||
m_nuclideTable = new QTableWidget(m_nuclideDialog);
|
||||
QStringList headers = { "核素", "射线类型", "能量(keV)","操作" };
|
||||
m_nuclideTable->setColumnCount(headers.size());
|
||||
|
|
@ -746,6 +759,7 @@ void NuclideAnalysisView::queryNuclidesForPeak(const PeakFitResultNuclide& peak)
|
|||
m_nuclideTable->setItem(i, 0, new QTableWidgetItem(m.nuclideName));
|
||||
m_nuclideTable->setItem(i, 1, new QTableWidgetItem(m.rayType));
|
||||
m_nuclideTable->setItem(i, 2, new QTableWidgetItem(m.energyDisplay));
|
||||
createRowOperationWidgets(i);
|
||||
}
|
||||
|
||||
if (matches.isEmpty()) {
|
||||
|
|
@ -771,4 +785,58 @@ bool NuclideAnalysisView::openNuclideDatabase()
|
|||
return false;
|
||||
}
|
||||
return db.openDatabase(dbPath, "nuclide_conn");
|
||||
}
|
||||
}
|
||||
|
||||
void NuclideAnalysisView::createRowOperationWidgets(int row)
|
||||
{
|
||||
QWidget* operationWidget = new QWidget(m_nuclideTable);
|
||||
QHBoxLayout* hLayout = new QHBoxLayout(operationWidget);
|
||||
hLayout->setContentsMargins(4, 2, 4, 2);
|
||||
hLayout->setSpacing(8);
|
||||
|
||||
// 复选框
|
||||
QCheckBox* checkBox = new QCheckBox(operationWidget);
|
||||
checkBox->setObjectName("rowCheckBox");
|
||||
hLayout->addWidget(checkBox);
|
||||
hLayout->addStretch();
|
||||
|
||||
// 删除按钮
|
||||
QPushButton* deleteBtn = new QPushButton(QStringLiteral(u"删除"), operationWidget);
|
||||
deleteBtn->setFixedWidth(50);
|
||||
deleteBtn->setProperty("rowIndex", row);
|
||||
connect(deleteBtn, &QPushButton::clicked, this, &NuclideAnalysisView::onDeleteRow);
|
||||
hLayout->addWidget(deleteBtn);
|
||||
|
||||
m_nuclideTable->setCellWidget(row, 3, operationWidget);
|
||||
}
|
||||
|
||||
void NuclideAnalysisView::onDeleteRow()
|
||||
{
|
||||
QPushButton* btn = qobject_cast<QPushButton*>(sender());
|
||||
if (!btn) return;
|
||||
|
||||
int row = btn->property("rowIndex").toInt();
|
||||
if (row >= 0 && row < m_nuclideTable->rowCount()) {
|
||||
m_nuclideTable->removeRow(row);
|
||||
// 更新后续行的rowIndex属性
|
||||
for (int i = row; i < m_nuclideTable->rowCount(); ++i) {
|
||||
QWidget* widget = m_nuclideTable->cellWidget(i, 3);
|
||||
if (widget) {
|
||||
QPushButton* delBtn = widget->findChild<QPushButton*>();
|
||||
if (delBtn) {
|
||||
delBtn->setProperty("rowIndex", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NuclideAnalysisView::onSaveSelectedNuclides()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void NuclideAnalysisView::onAddNuclide()
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@
|
|||
#include <QDialog>
|
||||
#include <QTableWidget>
|
||||
#include <QVBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QCheckBox>
|
||||
#include <QHBoxLayout>
|
||||
#include "sqlitemanager.h"
|
||||
|
||||
|
||||
|
|
@ -76,6 +79,8 @@ private:
|
|||
void queryNuclidesForPeak(const PeakFitResultNuclide& peak);
|
||||
bool openNuclideDatabase();
|
||||
|
||||
void createRowOperationWidgets(int row);
|
||||
|
||||
private slots:
|
||||
void onActionPlotConfigure();
|
||||
|
||||
|
|
@ -84,6 +89,11 @@ private slots:
|
|||
|
||||
void onActionPlotClear();
|
||||
|
||||
|
||||
void onDeleteRow();
|
||||
void onSaveSelectedNuclides();
|
||||
void onAddNuclide();
|
||||
|
||||
private:
|
||||
CustomQwtPlot* _plot = nullptr;
|
||||
QString _workspace;
|
||||
|
|
@ -109,5 +119,8 @@ private:
|
|||
|
||||
QDialog* m_nuclideDialog = nullptr;
|
||||
QTableWidget* m_nuclideTable = nullptr;
|
||||
QPushButton* m_saveBtn = nullptr;
|
||||
QPushButton* m_addBtn = nullptr; // 新增核素按钮
|
||||
|
||||
};
|
||||
#endif // NUCLIDEANALYSISVIEW_H
|
||||
Loading…
Reference in New Issue
Block a user