新增gvf转csv
This commit is contained in:
parent
7bd14d8179
commit
d8759e1318
|
|
@ -23,6 +23,7 @@
|
||||||
#include "EnergyScaleDataModel.h"
|
#include "EnergyScaleDataModel.h"
|
||||||
#include "DataCalcProcess/CoincidenceSpectrumProcess.h"
|
#include "DataCalcProcess/CoincidenceSpectrumProcess.h"
|
||||||
#include "BackgroundTaskListModel.h"
|
#include "BackgroundTaskListModel.h"
|
||||||
|
#include "GvfToCsv/GvfToCsv.h"
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
using namespace DataProcessWorkPool;
|
using namespace DataProcessWorkPool;
|
||||||
|
|
@ -1073,3 +1074,67 @@ bool EnergyScaleaAntiCoincidenceDataTask::processTask()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QString GvfToCsvDataTask::GetTaskName()
|
||||||
|
{
|
||||||
|
return QStringLiteral(u"[%1]GVF文件转CSV处理").arg(this->GetProjectName());
|
||||||
|
}
|
||||||
|
|
||||||
|
void GvfToCsvDataTask::setGvfName(const QString& gvfName)
|
||||||
|
{
|
||||||
|
m_gvfName = gvfName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GvfToCsvDataTask::setCsvName(const QString& csvName)
|
||||||
|
{
|
||||||
|
QDir projectDir(csvName);
|
||||||
|
if (!projectDir.exists()) {
|
||||||
|
projectDir.mkpath(".");
|
||||||
|
}
|
||||||
|
m_csvName = projectDir.filePath("粒子数据_gvf.csv");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GvfToCsvDataTask::processTask()
|
||||||
|
{
|
||||||
|
QFileInfo csvFileInfo(m_csvName);
|
||||||
|
QDir csvDir = csvFileInfo.absoluteDir();
|
||||||
|
|
||||||
|
if (!csvDir.exists()) {
|
||||||
|
if (!csvDir.mkpath(".")) {
|
||||||
|
m_error = QStringLiteral(u"无法创建输出目录: %1").arg(csvDir.path());
|
||||||
|
LOG_ERROR(m_error.toUtf8().constData());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString testFile = csvDir.filePath(".test_write.tmp");
|
||||||
|
QFile test(testFile);
|
||||||
|
if (!test.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||||
|
m_error = QStringLiteral(u"输出目录不可写: %1").arg(csvDir.path());
|
||||||
|
LOG_ERROR(m_error.toUtf8().constData());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
test.remove();
|
||||||
|
|
||||||
|
if (m_gvfName.isEmpty() || m_csvName.isEmpty()) {
|
||||||
|
m_error = "GVF文件路径或CSV输出路径为空";
|
||||||
|
LOG_ERROR(m_error.toUtf8().constData());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::unique_ptr<GvfToCsv> gvf2Csv(new GvfToCsv());
|
||||||
|
bool success = gvf2Csv->convertGVF2CSVSync(m_gvfName, m_csvName);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
m_resultCsvPath = m_csvName;
|
||||||
|
m_conversionSuccess = true;
|
||||||
|
updateTaskResultData(QVariant(m_resultCsvPath));
|
||||||
|
} else {
|
||||||
|
m_error = gvf2Csv->getLastError();
|
||||||
|
m_conversionSuccess = false;
|
||||||
|
LOG_ERROR(QStringLiteral(u"GVF转换失败: %1")
|
||||||
|
.arg(m_error)
|
||||||
|
.toUtf8().constData());
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_conversionSuccess;
|
||||||
|
}
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
#include "AnalysisTypeDefine.h"
|
#include "AnalysisTypeDefine.h"
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
#include <QEventLoop>
|
||||||
class EnergyScaleDataModel;
|
class EnergyScaleDataModel;
|
||||||
class MeasureAnalysisProjectModel;
|
class MeasureAnalysisProjectModel;
|
||||||
|
|
||||||
|
|
@ -167,6 +167,23 @@ namespace DataProcessWorkPool
|
||||||
private:
|
private:
|
||||||
virtual bool processTask() override;
|
virtual bool processTask() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class GvfToCsvDataTask : public DataProcessTask
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QString GetTaskName() override;
|
||||||
|
void setGvfName(const QString& gvfName);
|
||||||
|
void setCsvName(const QString& csvName);
|
||||||
|
QString getError() const { return m_error; }
|
||||||
|
QString getResultCsvPath() const { return m_resultCsvPath; }
|
||||||
|
private:
|
||||||
|
bool processTask() override;
|
||||||
|
QString m_gvfName;
|
||||||
|
QString m_csvName;
|
||||||
|
QString m_resultCsvPath;
|
||||||
|
QString m_error;
|
||||||
|
bool m_conversionSuccess = false;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // DATAPROCESSWORKPOOL_H
|
#endif // DATAPROCESSWORKPOOL_H
|
||||||
|
|
|
||||||
296
src/GvfToCsv/GvfToCsv.cpp
Normal file
296
src/GvfToCsv/GvfToCsv.cpp
Normal file
|
|
@ -0,0 +1,296 @@
|
||||||
|
#include "GvfToCsv.h"
|
||||||
|
#include <QFile>
|
||||||
|
#include <QTextStream>
|
||||||
|
#include <QEventLoop>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QDir>
|
||||||
|
#include "GlobalDefine.h"
|
||||||
|
GvfToCsv::GvfToCsv(QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
{
|
||||||
|
connect(m_sqliteWorker.get(), &SQLiteReadWrite::operationCompleted,
|
||||||
|
this, &GvfToCsv::onSqliteOperationCompleted);
|
||||||
|
connect(m_sqliteWorker.get(), &SQLiteReadWrite::progressUpdated,
|
||||||
|
this, &GvfToCsv::conversionProgress);
|
||||||
|
connect(m_sqliteWorker.get(), &SQLiteReadWrite::logMessage,
|
||||||
|
this, [](const QString &msg) { qDebug() << "[GVF转换日志]" << msg; });
|
||||||
|
}
|
||||||
|
|
||||||
|
GvfToCsv::~GvfToCsv()
|
||||||
|
{
|
||||||
|
cleanUp();
|
||||||
|
if (m_syncEventLoop) {
|
||||||
|
delete m_syncEventLoop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<ParticleData> GvfToCsv::parseParticleFrames(const QByteArray &data)
|
||||||
|
{
|
||||||
|
QList<ParticleData> particles;
|
||||||
|
const int minDataSize = GvfConst::HEADER_SIZE + GvfConst::PARTICLE_BLOCK_SIZE;
|
||||||
|
if (data.size() < minDataSize) {
|
||||||
|
qDebug() << "粒子数据长度不足,跳过解析";
|
||||||
|
return particles;
|
||||||
|
}
|
||||||
|
|
||||||
|
const quint8* rawData = reinterpret_cast<const quint8*>(data.constData());
|
||||||
|
if (rawData[0] != GvfConst::HEADER_BYTE1 || rawData[1] != GvfConst::HEADER_BYTE2) {
|
||||||
|
qDebug() << "粒子数据头部校验失败,跳过解析";
|
||||||
|
return particles;
|
||||||
|
}
|
||||||
|
|
||||||
|
const quint8* ptr = rawData + GvfConst::HEADER_SIZE;
|
||||||
|
int remaining = data.size() - GvfConst::HEADER_SIZE;
|
||||||
|
particles.reserve(remaining / GvfConst::PARTICLE_BLOCK_SIZE);
|
||||||
|
|
||||||
|
while (remaining >= GvfConst::PARTICLE_BLOCK_SIZE)
|
||||||
|
{
|
||||||
|
quint16 alignWord = qFromLittleEndian<quint16>(static_cast<const void*>(ptr));
|
||||||
|
quint8 lowByte = alignWord & 0xFF;
|
||||||
|
quint8 highByte = (alignWord >> 8) & 0xFF;
|
||||||
|
|
||||||
|
if (highByte != GvfConst::ALIGN_HIGH_BYTE) {
|
||||||
|
ptr += GvfConst::PARTICLE_BLOCK_SIZE;
|
||||||
|
remaining -= GvfConst::PARTICLE_BLOCK_SIZE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const quint8 board = (lowByte >> 4) & 0x0F;
|
||||||
|
const quint8 channel = lowByte & 0x0F;
|
||||||
|
const int channelIndex = board * 4 + channel;
|
||||||
|
|
||||||
|
if (channelIndex >= GvfConst::MAX_CHANNEL_COUNT) {
|
||||||
|
ptr += GvfConst::PARTICLE_BLOCK_SIZE;
|
||||||
|
remaining -= GvfConst::PARTICLE_BLOCK_SIZE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 timestamp = 0;
|
||||||
|
const quint8* timestampPtr = ptr + 2;
|
||||||
|
for (int i = 0; i < 6; ++i) {
|
||||||
|
timestamp |= static_cast<quint64>(timestampPtr[i]) << (8 * i);
|
||||||
|
}
|
||||||
|
|
||||||
|
const quint16 amplitude = qFromLittleEndian<quint16>(static_cast<const void*>(ptr + 8));
|
||||||
|
const quint32 icr = qFromLittleEndian<quint32>(static_cast<const void*>(ptr + 10));
|
||||||
|
const quint16 riseTime = qFromLittleEndian<quint16>(static_cast<const void*>(ptr + 14));
|
||||||
|
const quint16 fallTime = qFromLittleEndian<quint16>(static_cast<const void*>(ptr + 16));
|
||||||
|
|
||||||
|
const int address = static_cast<int>(
|
||||||
|
static_cast<double>(amplitude) / GvfConst::AMPLITUDE_MAX * GvfConst::MAX_ADDRESS
|
||||||
|
);
|
||||||
|
|
||||||
|
ParticleData p(
|
||||||
|
board,
|
||||||
|
channel,
|
||||||
|
timestamp,
|
||||||
|
timestamp * GvfConst::TIME_PER_COUNT,
|
||||||
|
amplitude,
|
||||||
|
address,
|
||||||
|
icr,
|
||||||
|
riseTime,
|
||||||
|
fallTime
|
||||||
|
);
|
||||||
|
|
||||||
|
particles.append(p);
|
||||||
|
ptr += GvfConst::PARTICLE_BLOCK_SIZE;
|
||||||
|
remaining -= GvfConst::PARTICLE_BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return particles;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GvfToCsv::cleanUp()
|
||||||
|
{
|
||||||
|
if (m_sqliteWorker) {
|
||||||
|
// 先断开所有信号连接
|
||||||
|
disconnect(m_sqliteWorker.get(), nullptr, this, nullptr);
|
||||||
|
// 停止操作
|
||||||
|
m_sqliteWorker->stopOperation();
|
||||||
|
|
||||||
|
// 等待操作完成
|
||||||
|
QEventLoop loop;
|
||||||
|
QTimer timeoutTimer;
|
||||||
|
timeoutTimer.setSingleShot(true);
|
||||||
|
|
||||||
|
connect(m_sqliteWorker.get(), &SQLiteReadWrite::operationCompleted, &loop, &QEventLoop::quit);
|
||||||
|
connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit);
|
||||||
|
|
||||||
|
timeoutTimer.start(3000);
|
||||||
|
loop.exec(QEventLoop::ExcludeUserInputEvents);
|
||||||
|
m_sqliteWorker.reset();
|
||||||
|
}
|
||||||
|
m_gvfPath.clear();
|
||||||
|
m_csvPath.clear();
|
||||||
|
m_lastError.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GvfToCsv::convertGVF2CSVSync(const QString &gvfPath, const QString &csvPath)
|
||||||
|
{
|
||||||
|
if (!m_syncEventLoop) {
|
||||||
|
m_syncEventLoop = new QEventLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
|
QObject signalReceiver;
|
||||||
|
|
||||||
|
connect(this, &GvfToCsv::conversionFinished, &signalReceiver, [&](bool success) {
|
||||||
|
result = success;
|
||||||
|
m_syncEventLoop->quit();
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(this, &GvfToCsv::errorOccurred, &signalReceiver, [](const QString &msg) {
|
||||||
|
LOG_ERROR(QStringLiteral(u"GVF转换错误: %1").arg(msg).toUtf8().constData());
|
||||||
|
});
|
||||||
|
|
||||||
|
convertGVF2CSVAsync(gvfPath, csvPath);
|
||||||
|
|
||||||
|
m_syncEventLoop->exec();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GvfToCsv::convertGVF2CSVAsync(const QString &gvfPath, const QString &csvPath)
|
||||||
|
{
|
||||||
|
m_lastError.clear();
|
||||||
|
cleanUp();
|
||||||
|
|
||||||
|
if (gvfPath.isEmpty() || csvPath.isEmpty()) {
|
||||||
|
setLastError("GVF/CSV路径不能为空");
|
||||||
|
emit conversionFinished(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFileInfo gvfFileInfo(gvfPath);
|
||||||
|
if (!gvfFileInfo.exists() || !gvfFileInfo.isFile()) {
|
||||||
|
setLastError(QString("GVF文件不存在: %1").arg(gvfPath));
|
||||||
|
emit conversionFinished(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFileInfo csvFileInfo(csvPath);
|
||||||
|
QDir csvDir = csvFileInfo.absoluteDir();
|
||||||
|
if (!csvDir.exists() && !csvDir.mkpath(".")) {
|
||||||
|
setLastError(QString("无法创建CSV目录: %1").arg(csvDir.path()));
|
||||||
|
emit conversionFinished(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_gvfPath = gvfPath;
|
||||||
|
m_csvPath = csvPath;
|
||||||
|
|
||||||
|
m_sqliteWorker = std::make_unique<SQLiteReadWrite>(this);
|
||||||
|
|
||||||
|
connect(m_sqliteWorker.get(), &SQLiteReadWrite::operationCompleted,
|
||||||
|
this, &GvfToCsv::onSqliteOperationCompleted, Qt::QueuedConnection);
|
||||||
|
connect(m_sqliteWorker.get(), &SQLiteReadWrite::progressUpdated,
|
||||||
|
this, &GvfToCsv::conversionProgress, Qt::QueuedConnection);
|
||||||
|
if (!m_sqliteWorker->openDatabase(m_gvfPath)) {
|
||||||
|
setLastError(QString("打开GVF数据库失败: %1").arg(m_gvfPath));
|
||||||
|
emit conversionFinished(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_sqliteWorker->startReadWriteOperation();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GvfToCsv::onSqliteOperationCompleted(bool success, const QString &msg)
|
||||||
|
{
|
||||||
|
if (!success) {
|
||||||
|
setLastError(QString("GVF数据读取失败: %1").arg(msg));
|
||||||
|
cleanUp();
|
||||||
|
emit conversionFinished(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
processDBData();
|
||||||
|
emit conversionFinished(true);
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
setLastError(QString("CSV写入异常: %1").arg(e.what()));
|
||||||
|
emit conversionFinished(false);
|
||||||
|
} catch (...) {
|
||||||
|
setLastError("CSV写入未知异常");
|
||||||
|
emit conversionFinished(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GvfToCsv::processDBData()
|
||||||
|
{
|
||||||
|
QVector<DataBaseStruct> dbList = m_sqliteWorker->DataBaseList();
|
||||||
|
if (dbList.isEmpty()) {
|
||||||
|
throw std::runtime_error("GVF数据库中无任何记录");
|
||||||
|
}
|
||||||
|
QFile outFile(m_csvPath);
|
||||||
|
if (!outFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
|
||||||
|
throw std::runtime_error(QString("无法创建CSV文件: %1,错误: %2")
|
||||||
|
.arg(m_csvPath)
|
||||||
|
.arg(outFile.errorString())
|
||||||
|
.toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextStream out(&outFile);
|
||||||
|
out.setCodec("UTF-8");
|
||||||
|
out << QStringLiteral(u"板卡号,通道号,道址,时间计数\n");
|
||||||
|
|
||||||
|
QString csvBuffer;
|
||||||
|
csvBuffer.reserve(4 * 1024 * 1024); // 4MB缓冲区
|
||||||
|
|
||||||
|
quint64 totalParticles = 0;
|
||||||
|
int emptyFrameCount = 0;
|
||||||
|
int processedFrames = 0;
|
||||||
|
const int totalFrames = dbList.size();
|
||||||
|
|
||||||
|
for (const auto &data : dbList) {
|
||||||
|
QList<ParticleData> particles = parseParticleFrames(data.data);
|
||||||
|
if (particles.isEmpty()) {
|
||||||
|
emptyFrameCount++;
|
||||||
|
} else {
|
||||||
|
totalParticles += particles.size();
|
||||||
|
|
||||||
|
for (const auto &p : particles) {
|
||||||
|
csvBuffer += QString("%1,%2,%3,%4\n")
|
||||||
|
.arg(p.boardId)
|
||||||
|
.arg(p.channelId)
|
||||||
|
.arg(p.address)
|
||||||
|
.arg(p.timestampCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (csvBuffer.size() >= 4 * 1024 * 1024) {
|
||||||
|
out << csvBuffer;
|
||||||
|
csvBuffer.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
processedFrames++;
|
||||||
|
if (processedFrames % 1000 == 0) {
|
||||||
|
int remainingFrames = totalFrames - processedFrames;
|
||||||
|
int progress = (processedFrames * 100) / totalFrames;
|
||||||
|
emit conversionProgress(progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!csvBuffer.isEmpty()) {
|
||||||
|
out << csvBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
out.flush();
|
||||||
|
outFile.close();
|
||||||
|
|
||||||
|
if (outFile.error() != QFile::NoError) {
|
||||||
|
throw std::runtime_error(QString("CSV文件写入失败: %1,错误: %2")
|
||||||
|
.arg(m_csvPath)
|
||||||
|
.arg(outFile.errorString())
|
||||||
|
.toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totalParticles == 0) {
|
||||||
|
QFile::remove(m_csvPath);
|
||||||
|
throw std::runtime_error(QString("GVF文件中未解析到任何有效粒子数据,空帧数: %1")
|
||||||
|
.arg(emptyFrameCount)
|
||||||
|
.toStdString());
|
||||||
|
}
|
||||||
|
emit conversionProgress(100);
|
||||||
|
}
|
||||||
88
src/GvfToCsv/GvfToCsv.h
Normal file
88
src/GvfToCsv/GvfToCsv.h
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
#ifndef GVFTOCSV_H
|
||||||
|
#define GVFTOCSV_H
|
||||||
|
|
||||||
|
#include "sqliteread.h"
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <memory>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QtCore>
|
||||||
|
#include <QtEndian>
|
||||||
|
// 常量定义:替换魔法数,提升可读性和可维护性
|
||||||
|
namespace GvfConst {
|
||||||
|
constexpr quint8 HEADER_BYTE1 = 0xA7; // 头部固定字节1
|
||||||
|
constexpr quint8 HEADER_BYTE2 = 0xA2; // 头部固定字节2
|
||||||
|
constexpr int HEADER_SIZE = 3; // 头部总字节数
|
||||||
|
constexpr int PARTICLE_BLOCK_SIZE = 20; // 单个粒子数据块大小
|
||||||
|
constexpr quint8 ALIGN_HIGH_BYTE = 0xFE; // 对齐标记高字节
|
||||||
|
constexpr int MAX_CHANNEL_COUNT = 32; // 硬件最大通道数
|
||||||
|
constexpr double CLOCK_FREQ_MHZ = 200.0; // 时钟频率(200MHz)
|
||||||
|
constexpr double TIME_PER_COUNT = 1.0 / (CLOCK_FREQ_MHZ * 1e6); // 单计数时间(5ns)
|
||||||
|
constexpr int MAX_ADDRESS = 4096; // 最大道址
|
||||||
|
constexpr int AMPLITUDE_MAX = 65535; // 幅度最大值
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ParticleData {
|
||||||
|
int boardId = 0; // 板卡号 (0-15)
|
||||||
|
int channelId = 0; // 通道号 (0-15)
|
||||||
|
quint64 timestampCount = 0; // 原始时间计数(6字节)
|
||||||
|
double timeSeconds = 0.0; // 换算后的时间(秒)
|
||||||
|
quint16 amplitude = 0; // 原始幅度值 (0-65535)
|
||||||
|
int address = 0; // 转换后的道址
|
||||||
|
quint32 icr = 0; // 输入计数率相关值
|
||||||
|
quint16 riseTime = 0; // 上升时间
|
||||||
|
quint16 fallTime = 0; // 下降时间
|
||||||
|
|
||||||
|
// 添加构造函数
|
||||||
|
ParticleData() = default; // 保留默认构造
|
||||||
|
ParticleData(int board, int ch, quint64 ts, double ts_sec,
|
||||||
|
quint16 amp, int addr, quint32 icr_val,
|
||||||
|
quint16 rise, quint16 fall)
|
||||||
|
: boardId(board)
|
||||||
|
, channelId(ch)
|
||||||
|
, timestampCount(ts)
|
||||||
|
, timeSeconds(ts_sec)
|
||||||
|
, amplitude(amp)
|
||||||
|
, address(addr)
|
||||||
|
, icr(icr_val)
|
||||||
|
, riseTime(rise)
|
||||||
|
, fallTime(fall)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
class GvfToCsv : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit GvfToCsv(QObject *parent = nullptr);
|
||||||
|
~GvfToCsv() override;
|
||||||
|
|
||||||
|
void convertGVF2CSVAsync(const QString &gvfPath, const QString &csvPath);
|
||||||
|
// 添加同步转换方法
|
||||||
|
bool convertGVF2CSVSync(const QString &gvfPath, const QString &csvPath);
|
||||||
|
// 添加错误信息获取
|
||||||
|
QString getLastError() const { return m_lastError; }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void conversionProgress(int percent);
|
||||||
|
void conversionFinished(bool success);
|
||||||
|
void errorOccurred(const QString &msg);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onSqliteOperationCompleted(bool success, const QString &msg);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void processDBData();
|
||||||
|
QList<ParticleData> parseParticleFrames(const QByteArray &data);
|
||||||
|
void cleanUp();
|
||||||
|
// 添加错误信息存储
|
||||||
|
void setLastError(const QString& error) { m_lastError = error; emit errorOccurred(error); }
|
||||||
|
|
||||||
|
std::unique_ptr<SQLiteReadWrite> m_sqliteWorker;
|
||||||
|
QString m_gvfPath;
|
||||||
|
QString m_csvPath;
|
||||||
|
QString m_lastError;
|
||||||
|
// 用于同步转换
|
||||||
|
QEventLoop* m_syncEventLoop = nullptr;
|
||||||
|
};
|
||||||
|
#endif // GVFTOCSV_H
|
||||||
276
src/GvfToCsv/sqliteread.cpp
Normal file
276
src/GvfToCsv/sqliteread.cpp
Normal file
|
|
@ -0,0 +1,276 @@
|
||||||
|
#include "sqliteread.h"
|
||||||
|
#include <QtConcurrent>
|
||||||
|
SQLiteReadWrite::SQLiteReadWrite(QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
{
|
||||||
|
m_connectionName = QString("SQLiteConnection_%1").arg(reinterpret_cast<quintptr>(this));
|
||||||
|
idValue = 0;
|
||||||
|
m_stopRequested = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SQLiteReadWrite::~SQLiteReadWrite()
|
||||||
|
{
|
||||||
|
if (!m_isClosed) {
|
||||||
|
closeDatabase();
|
||||||
|
}
|
||||||
|
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SQLiteReadWrite::openDatabase(const QString &dbPath)
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&m_mutex);
|
||||||
|
|
||||||
|
if (!m_isClosed) {
|
||||||
|
closeDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确定数据库路径
|
||||||
|
QString path = dbPath;
|
||||||
|
if (path.isEmpty()) {
|
||||||
|
QString appDir = QCoreApplication::applicationDirPath();
|
||||||
|
path = QDir(appDir).filePath("test_readwrite.db");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dbPath = path;
|
||||||
|
|
||||||
|
// 打开数据库
|
||||||
|
m_database = QSqlDatabase::addDatabase("QSQLITE", m_connectionName);
|
||||||
|
m_database.setDatabaseName(m_dbPath);
|
||||||
|
|
||||||
|
if (!m_database.open()) {
|
||||||
|
log(QString("打开数据库失败: %1").arg(m_database.lastError().text()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 启用外键和WAL模式(提高并发性能)
|
||||||
|
QSqlQuery query(m_database);
|
||||||
|
// 开启外键约束
|
||||||
|
if (!query.exec("PRAGMA foreign_keys = ON;")) {
|
||||||
|
log(QString("启用外键失败: %1").arg(query.lastError().text()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开启WAL模式(写时复制,提高读写并发性能)
|
||||||
|
if (!query.exec("PRAGMA journal_mode = WAL;")) {
|
||||||
|
log(QString("启用WAL模式失败: %1").arg(query.lastError().text()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// // 设置同步模式(在安全性和性能之间权衡)
|
||||||
|
// if (!query.exec("PRAGMA synchronous = NORMAL;")) {
|
||||||
|
// log(QString("设置同步模式失败: %1").arg(query.lastError().text()));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 设置缓存大小
|
||||||
|
if (!query.exec("PRAGMA cache_size = 10000;")) {
|
||||||
|
log(QString("设置缓存大小失败: %1").arg(query.lastError().text()));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_isClosed = false;
|
||||||
|
log(QString("数据库打开成功: %1").arg(m_dbPath));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SQLiteReadWrite::closeDatabase()
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&m_mutex);
|
||||||
|
|
||||||
|
if (m_isClosed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_isClosed = true;
|
||||||
|
|
||||||
|
if (m_database.isOpen()) {
|
||||||
|
m_database.close();
|
||||||
|
log("数据库已关闭");
|
||||||
|
}
|
||||||
|
if (QSqlDatabase::contains(m_connectionName)) {
|
||||||
|
QSqlDatabase::removeDatabase(m_connectionName);
|
||||||
|
}
|
||||||
|
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SQLiteReadWrite::startReadWriteOperation()
|
||||||
|
{
|
||||||
|
if (!m_database.isOpen()) {
|
||||||
|
emit operationCompleted(false, "数据库未打开");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_stopRequested = false;
|
||||||
|
//在单独的线程中执行,避免阻塞UI
|
||||||
|
QtConcurrent::run(this, &SQLiteReadWrite::processReadWrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SQLiteReadWrite::stopOperation()
|
||||||
|
{
|
||||||
|
m_stopRequested = true;
|
||||||
|
log("stop requese send");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SQLiteReadWrite::processReadWrite()
|
||||||
|
{
|
||||||
|
m_timer.start();
|
||||||
|
log("开始边读边写操作...");
|
||||||
|
try {
|
||||||
|
processWithMultipleConnections();
|
||||||
|
if (!m_stopRequested) {
|
||||||
|
qint64 elapsed = m_timer.elapsed();
|
||||||
|
QString message = QString("操作完成,总耗时: %1 毫秒").arg(elapsed);
|
||||||
|
log(message);
|
||||||
|
emit operationCompleted(true, message);
|
||||||
|
} else {
|
||||||
|
emit operationCompleted(false, "quxiao");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
log(QString("发生异常: %1").arg(e.what()));
|
||||||
|
emit operationCompleted(false, QString("异常: %1").arg(e.what()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SQLiteReadWrite::processWithMultipleConnections()
|
||||||
|
{
|
||||||
|
const QString readConnName = m_connectionName + "_read";
|
||||||
|
|
||||||
|
int totalRecords = 0;
|
||||||
|
int processedRecords = 0;
|
||||||
|
bool readSuccess = false;
|
||||||
|
|
||||||
|
{
|
||||||
|
QSqlDatabase readDb = QSqlDatabase::addDatabase("QSQLITE", readConnName);
|
||||||
|
readDb.setDatabaseName(m_dbPath);
|
||||||
|
|
||||||
|
if (!readDb.open()) {
|
||||||
|
QString logMsg = QString("打开读取连接失败: %1").arg(readDb.lastError().text());
|
||||||
|
log(logMsg.toUtf8().constData());
|
||||||
|
emit operationCompleted(false, "无法打开数据库连接");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
QSqlQuery optimizeQuery(readDb);
|
||||||
|
optimizeQuery.exec("PRAGMA journal_mode = WAL;");
|
||||||
|
optimizeQuery.exec("PRAGMA synchronous = OFF;");
|
||||||
|
optimizeQuery.exec("PRAGMA cache_size = -200000;"); // 200MB缓存
|
||||||
|
optimizeQuery.exec("PRAGMA temp_store = MEMORY;");
|
||||||
|
optimizeQuery.exec("PRAGMA mmap_size = 2147483648;"); // 2GB内存映射
|
||||||
|
optimizeQuery.exec("PRAGMA query_only = ON;");
|
||||||
|
optimizeQuery.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
QSqlQuery countQuery(readDb);
|
||||||
|
if (countQuery.exec("SELECT COUNT(*) FROM lmdatainfov2")) {
|
||||||
|
countQuery.next();
|
||||||
|
totalRecords = countQuery.value(0).toInt();
|
||||||
|
}
|
||||||
|
countQuery.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totalRecords == 0) {
|
||||||
|
log("数据库中无记录");
|
||||||
|
readDb.close();
|
||||||
|
emit operationCompleted(false, "数据库中无有效数据");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString totalMsg = QString("GVF数据库总记录数: %1 条").arg(totalRecords);
|
||||||
|
log(totalMsg.toUtf8().constData());
|
||||||
|
|
||||||
|
const int pageSize = 200;
|
||||||
|
int lastId = 0;
|
||||||
|
|
||||||
|
m_DataBaseList.clear();
|
||||||
|
m_DataBaseList.reserve(totalRecords);
|
||||||
|
|
||||||
|
while (!m_stopRequested) {
|
||||||
|
QSqlQuery readQuery(readDb);
|
||||||
|
readQuery.setForwardOnly(true);
|
||||||
|
readQuery.prepare("SELECT id, data FROM lmdatainfov2 WHERE id > :lastId ORDER BY id LIMIT :limit");
|
||||||
|
readQuery.bindValue(":lastId", lastId);
|
||||||
|
readQuery.bindValue(":limit", pageSize);
|
||||||
|
|
||||||
|
if (!readQuery.exec()) {
|
||||||
|
QString errMsg = QString("数据读取失败: %1").arg(readQuery.lastError().text());
|
||||||
|
log(errMsg.toUtf8().constData());
|
||||||
|
readQuery.finish();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pageRecords = 0;
|
||||||
|
while (readQuery.next() && !m_stopRequested) {
|
||||||
|
DataBaseStruct data;
|
||||||
|
data.id = readQuery.value(0).toInt();
|
||||||
|
data.data = readQuery.value(1).toByteArray();
|
||||||
|
m_DataBaseList.append(data);
|
||||||
|
lastId = data.id;
|
||||||
|
pageRecords++;
|
||||||
|
}
|
||||||
|
|
||||||
|
readQuery.finish();
|
||||||
|
readQuery.clear();
|
||||||
|
|
||||||
|
if (pageRecords == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
processedRecords += pageRecords;
|
||||||
|
int remainingRecords = totalRecords - processedRecords;
|
||||||
|
int progress = (processedRecords * 100) / totalRecords;
|
||||||
|
emit progressUpdated(progress, processedRecords, totalRecords);
|
||||||
|
}
|
||||||
|
|
||||||
|
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||||
|
readDb.close();
|
||||||
|
readSuccess = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QThread::msleep(50);
|
||||||
|
|
||||||
|
if (QSqlDatabase::contains(readConnName)) {
|
||||||
|
QSqlDatabase::removeDatabase(readConnName);
|
||||||
|
}
|
||||||
|
|
||||||
|
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
QSqlDatabase SQLiteReadWrite::createConnection()
|
||||||
|
{
|
||||||
|
QString connName = QString("TempConnection_%1_%2")
|
||||||
|
.arg(m_connectionName)
|
||||||
|
.arg(QDateTime::currentMSecsSinceEpoch());
|
||||||
|
|
||||||
|
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", connName);
|
||||||
|
db.setDatabaseName(m_dbPath);
|
||||||
|
|
||||||
|
if (!db.open()) {
|
||||||
|
log(QString("创建临时连接失败: %1").arg(db.lastError().text()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return db;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SQLiteReadWrite::log(const QString &message)
|
||||||
|
{
|
||||||
|
QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss.zzz");
|
||||||
|
QString logMsg = QString("[%1] %2").arg(timestamp).arg(message);
|
||||||
|
|
||||||
|
emit logMessage(logMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<DataBaseStruct> SQLiteReadWrite::DataBaseList() const
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&m_mutex);
|
||||||
|
return m_DataBaseList;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SQLiteReadWrite::setIdValue(int value)
|
||||||
|
{
|
||||||
|
idValue = value;
|
||||||
|
}
|
||||||
89
src/GvfToCsv/sqliteread.h
Normal file
89
src/GvfToCsv/sqliteread.h
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
// sqlitereadwrite.h
|
||||||
|
#ifndef SQLITERREADWRITE_H
|
||||||
|
#define SQLITERREADWRITE_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QSqlDatabase>
|
||||||
|
#include <QSqlQuery>
|
||||||
|
#include <QSqlError>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QAtomicInteger>
|
||||||
|
#include <QElapsedTimer>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
struct DataBaseStruct
|
||||||
|
{
|
||||||
|
int id;//ID
|
||||||
|
int curdevconfigindex;
|
||||||
|
int orgdevconfigindex;
|
||||||
|
int icr;
|
||||||
|
int datanum;
|
||||||
|
int tick;
|
||||||
|
QByteArray data;
|
||||||
|
QString reserve;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SQLiteReadWrite : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit SQLiteReadWrite(QObject *parent = nullptr);
|
||||||
|
~SQLiteReadWrite();
|
||||||
|
|
||||||
|
bool openDatabase(const QString &dbPath);
|
||||||
|
void closeDatabase();
|
||||||
|
|
||||||
|
// 边读边写操作
|
||||||
|
void startReadWriteOperation();
|
||||||
|
void stopOperation();
|
||||||
|
|
||||||
|
void setIdValue(int value);
|
||||||
|
|
||||||
|
QVector<DataBaseStruct> DataBaseList() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void progressUpdated(int percent, qint64 processed, qint64 total);
|
||||||
|
void operationCompleted(bool success, const QString &message);
|
||||||
|
void logMessage(const QString &message);
|
||||||
|
void emitReadId(int readId);
|
||||||
|
void emitStopTime();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void processReadWrite();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// 数据库连接管理
|
||||||
|
QSqlDatabase m_database;
|
||||||
|
QString m_dbPath;
|
||||||
|
|
||||||
|
// 线程安全
|
||||||
|
mutable QMutex m_mutex;
|
||||||
|
QAtomicInteger<bool> m_stopRequested{false};
|
||||||
|
|
||||||
|
// 性能统计
|
||||||
|
QElapsedTimer m_timer;
|
||||||
|
|
||||||
|
// 连接名(确保多线程连接唯一性)
|
||||||
|
QString m_connectionName;
|
||||||
|
|
||||||
|
// 私有方法
|
||||||
|
QSqlDatabase createConnection();
|
||||||
|
|
||||||
|
|
||||||
|
// 具体操作
|
||||||
|
void processWithMultipleConnections();
|
||||||
|
|
||||||
|
void log(const QString &message);
|
||||||
|
|
||||||
|
int idValue;
|
||||||
|
|
||||||
|
QVector<DataBaseStruct> m_DataBaseList;
|
||||||
|
|
||||||
|
bool m_isClosed = true;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SQLITERREADWRITE_H
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>892</width>
|
<width>892</width>
|
||||||
<height>23</height>
|
<height>21</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QMenu" name="menu_measurement_analysis">
|
<widget class="QMenu" name="menu_measurement_analysis">
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include "DataProcessWorkPool.h"
|
#include "DataProcessWorkPool.h"
|
||||||
|
#include "GlobalDefine.h"
|
||||||
NewMeasureAnalysisDlg::NewMeasureAnalysisDlg(QWidget *parent)
|
NewMeasureAnalysisDlg::NewMeasureAnalysisDlg(QWidget *parent)
|
||||||
: QDialog(parent)
|
: QDialog(parent)
|
||||||
, ui(new Ui::NewMeasureAnalysisDlg)
|
, ui(new Ui::NewMeasureAnalysisDlg)
|
||||||
|
|
@ -242,17 +242,33 @@ void NewMeasureAnalysisDlg::on_btn_ok_clicked()
|
||||||
QMessageBox::warning(this, QStringLiteral(u"警告"), QStringLiteral(u"创建测量分析项目工作目录失败:\n%1!").arg(project_dir_path));
|
QMessageBox::warning(this, QStringLiteral(u"警告"), QStringLiteral(u"创建测量分析项目工作目录失败:\n%1!").arg(project_dir_path));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ( ui->checkBox_file_data->isChecked() ) {
|
if ( ui->checkBox_file_data->isChecked() )
|
||||||
|
{
|
||||||
const QString& data_file_path = ui->lineEdit_filename->property("data_file_path").toString();
|
const QString& data_file_path = ui->lineEdit_filename->property("data_file_path").toString();
|
||||||
if (data_file_path.isEmpty()) {
|
if (data_file_path.isEmpty()) {
|
||||||
QMessageBox::warning(this, QStringLiteral(u"警告"), QStringLiteral(u"请选择粒子数据文件!"));
|
QMessageBox::warning(this, QStringLiteral(u"警告"), QStringLiteral(u"请选择粒子数据文件!"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto separate_task = new DataProcessWorkPool::ParticleDataSortByMinimysTask;
|
|
||||||
separate_task->SetAllChannelParticleDataFilename(data_file_path);
|
if(QFileInfo(data_file_path).suffix().toLower() == "gvf")
|
||||||
separate_task->SetSortedResultDir(project_dir_path);
|
{
|
||||||
separate_task->SetFinishedNotifier(this, "onNewProjectFromFileFinished", project_name);
|
// 正确使用任务池处理GVF转换
|
||||||
separate_task->StartTask();
|
auto gvfTask = new DataProcessWorkPool::GvfToCsvDataTask;
|
||||||
|
gvfTask->setGvfName(data_file_path);
|
||||||
|
gvfTask->setCsvName(project_dir_path);
|
||||||
|
gvfTask->SetFinishedNotifier(this, "onGvfConversionFinished", project_name);
|
||||||
|
gvfTask->StartTask();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 直接处理CSV文件
|
||||||
|
startParticleSortTask(data_file_path, project_name, project_dir_path);
|
||||||
|
}
|
||||||
|
// auto separate_task = new DataProcessWorkPool::ParticleDataSortByMinimysTask;
|
||||||
|
// separate_task->SetAllChannelParticleDataFilename(data_file_path);
|
||||||
|
// separate_task->SetSortedResultDir(project_dir_path);
|
||||||
|
// separate_task->SetFinishedNotifier(this, "onNewProjectFromFileFinished", project_name);
|
||||||
|
// separate_task->StartTask();
|
||||||
|
|
||||||
ui->stackedWidget->setEnabled(false);
|
ui->stackedWidget->setEnabled(false);
|
||||||
ui->label_note->setEnabled(false);
|
ui->label_note->setEnabled(false);
|
||||||
|
|
@ -274,3 +290,59 @@ void NewMeasureAnalysisDlg::on_btn_ok_clicked()
|
||||||
// separate_task->SetFinishedNotifier(this->_tree_measure_analysis, "onFinishedSeparateEveryChannelParticleData", project_name);
|
// separate_task->SetFinishedNotifier(this->_tree_measure_analysis, "onFinishedSeparateEveryChannelParticleData", project_name);
|
||||||
// separate_task->StartTask();
|
// separate_task->StartTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加新的槽函数处理GVF转换完成
|
||||||
|
void NewMeasureAnalysisDlg::onGvfConversionFinished(bool ok, const QString& project_name, const QVariant &data)
|
||||||
|
{
|
||||||
|
this->_task_wait_timer->stop();
|
||||||
|
ui->progressBar->setValue(100);
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
QString csvFilePath = data.toString();
|
||||||
|
QFileInfo fileInfo(csvFilePath);
|
||||||
|
|
||||||
|
if (fileInfo.exists() && fileInfo.size() > 100) {
|
||||||
|
startParticleSortTask(csvFilePath, project_name, fileInfo.absolutePath());
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
ok = false;
|
||||||
|
QString errorMsg;
|
||||||
|
if (!fileInfo.exists()) {
|
||||||
|
errorMsg = QStringLiteral(u"输出文件不存在: %1").arg(csvFilePath);
|
||||||
|
} else {
|
||||||
|
errorMsg = QStringLiteral(u"输出文件为空: %1").arg(csvFilePath);
|
||||||
|
QFile::remove(csvFilePath);
|
||||||
|
}
|
||||||
|
LOG_ERROR(errorMsg.toUtf8().constData());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QString projects_dir_path = QDir(qApp->applicationDirPath()).filePath("Projects");
|
||||||
|
QString project_dir_path = QDir(projects_dir_path).filePath(project_name);
|
||||||
|
QDir project_dir(project_dir_path);
|
||||||
|
if (project_dir.exists()) {
|
||||||
|
project_dir.removeRecursively();
|
||||||
|
}
|
||||||
|
|
||||||
|
QMessageBox::critical(this, QStringLiteral(u"GVF转换失败"),
|
||||||
|
QStringLiteral(u"错误信息: %1\n\n请检查GVF文件格式是否正确。")
|
||||||
|
.arg(data.isValid() ? data.toString() : "未知错误"));
|
||||||
|
|
||||||
|
ui->progressBar->setVisible(false);
|
||||||
|
ui->stackedWidget->setEnabled(true);
|
||||||
|
ui->label_note->setEnabled(true);
|
||||||
|
ui->plainTextEdit_description->setEnabled(true);
|
||||||
|
ui->btn_previous_step->setEnabled(true);
|
||||||
|
ui->btn_next_step->setEnabled(true);
|
||||||
|
ui->btn_ok->setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NewMeasureAnalysisDlg::startParticleSortTask(const QString& data_file_path,
|
||||||
|
const QString& project_name,
|
||||||
|
const QString& project_dir_path)
|
||||||
|
{
|
||||||
|
auto separate_task = new DataProcessWorkPool::ParticleDataSortByMinimysTask;
|
||||||
|
separate_task->SetAllChannelParticleDataFilename(data_file_path);
|
||||||
|
separate_task->SetSortedResultDir(project_dir_path);
|
||||||
|
separate_task->SetFinishedNotifier(this, "onNewProjectFromFileFinished", project_name);
|
||||||
|
separate_task->StartTask();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,13 @@ public:
|
||||||
private:
|
private:
|
||||||
void initialization();
|
void initialization();
|
||||||
void newProject(const QString &particle_data_filename = QString());
|
void newProject(const QString &particle_data_filename = QString());
|
||||||
|
void startParticleSortTask(const QString& data_file_path,
|
||||||
|
const QString& project_name,
|
||||||
|
const QString& project_dir_path);
|
||||||
private slots:
|
private slots:
|
||||||
void onNewProjectFromFileFinished(bool ok, const QString& project_name, const QVariant &data);
|
void onNewProjectFromFileFinished(bool ok, const QString& project_name, const QVariant &data);
|
||||||
void on_btn_ok_clicked();
|
void on_btn_ok_clicked();
|
||||||
|
void onGvfConversionFinished(bool ok, const QString& project_name, const QVariant &data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::NewMeasureAnalysisDlg *ui;
|
Ui::NewMeasureAnalysisDlg *ui;
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,8 @@ SOURCES += \
|
||||||
EnergyCountPlotView/EnergyCountPlotView.cpp \
|
EnergyCountPlotView/EnergyCountPlotView.cpp \
|
||||||
EnergyScaleDataModel.cpp \
|
EnergyScaleDataModel.cpp \
|
||||||
EnergyScaleForm.cpp \
|
EnergyScaleForm.cpp \
|
||||||
|
GvfToCsv/GvfToCsv.cpp \
|
||||||
|
GvfToCsv/sqliteread.cpp \
|
||||||
MainWindow.cpp \
|
MainWindow.cpp \
|
||||||
MeasureAnalysisDataTableView/MeasureAnalysisDataTableView.cpp \
|
MeasureAnalysisDataTableView/MeasureAnalysisDataTableView.cpp \
|
||||||
MeasureAnalysisHistoryForm/MeasureAnalysisHistoryForm.cpp \
|
MeasureAnalysisHistoryForm/MeasureAnalysisHistoryForm.cpp \
|
||||||
|
|
@ -136,6 +138,8 @@ HEADERS += \
|
||||||
EnergyScaleDataModel.h \
|
EnergyScaleDataModel.h \
|
||||||
EnergyScaleForm.h \
|
EnergyScaleForm.h \
|
||||||
GlobalDefine.h \
|
GlobalDefine.h \
|
||||||
|
GvfToCsv/GvfToCsv.h \
|
||||||
|
GvfToCsv/sqliteread.h \
|
||||||
MainWindow.h \
|
MainWindow.h \
|
||||||
MeasureAnalysisDataTableView/MeasureAnalysisDataTableView.h \
|
MeasureAnalysisDataTableView/MeasureAnalysisDataTableView.h \
|
||||||
MeasureAnalysisHistoryForm/MeasureAnalysisHistoryForm.h \
|
MeasureAnalysisHistoryForm/MeasureAnalysisHistoryForm.h \
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user