增加道址计数
This commit is contained in:
parent
7cda2890ce
commit
02cb0839b9
|
|
@ -33,7 +33,10 @@
|
|||
#include <QJsonObject>
|
||||
#include "MeasureClient.h"
|
||||
#include "MeasureAnalysisDataTableView.h"
|
||||
#include "GvfToCsv/GvfToCsv.h"
|
||||
#include "csv.h"
|
||||
#include <fstream>
|
||||
|
||||
using namespace io;
|
||||
using namespace ads;
|
||||
|
||||
MainWindow* MainWindow::_s_main_win = nullptr;
|
||||
|
|
@ -383,6 +386,8 @@ void MainWindow::closeProject(const QString& project_name)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MainWindow::showEvent(QShowEvent *event)
|
||||
{
|
||||
QMainWindow::showEvent(event);
|
||||
|
|
@ -476,6 +481,15 @@ void MainWindow::on_action_start_measure_triggered()
|
|||
QString item_name = QStringLiteral(u"测量粒子数据");
|
||||
QStandardItem * particleData = node[item_name];
|
||||
ProjectList::Instance()->SetNodeStatus(particleData,status,true);
|
||||
//创建通道道址计数文件夹
|
||||
const QString& all_channel_particle_data_filename = models->GetAllChannelParticleDataFilename();
|
||||
const QString& all_ch_count_dir = models->GetProjectDir();
|
||||
|
||||
if (!all_channel_particle_data_filename.isEmpty()) {
|
||||
const QString& every_ch_count_dir = QDir(models->GetProjectDir()).filePath(QStringLiteral(u"通道道址计数"));
|
||||
QDir every_ch_count_output_dir(every_ch_count_dir);
|
||||
every_ch_count_output_dir.mkpath(every_ch_count_dir);
|
||||
}
|
||||
|
||||
QString projectName;
|
||||
QString deviceCfg;
|
||||
|
|
@ -586,7 +600,6 @@ void MainWindow::onRunningInfo(const QString &run_info)
|
|||
|
||||
void MainWindow::onGvfData(const QByteArray &data)
|
||||
{
|
||||
// LOG_INFO(QStringLiteral(u"GVFDATA: %1").arg(QString::fromUtf8(data.toHex().toUpper())));
|
||||
QList<ParticleData> particles = _gvfToCsv->parseParticleFrames(data);
|
||||
if (particles.isEmpty()) {
|
||||
LOG_INFO(QStringLiteral(u"本次GVF数据未解析到有效粒子,跳过写入CSV"));
|
||||
|
|
@ -625,9 +638,19 @@ void MainWindow::onGvfData(const QByteArray &data)
|
|||
out << csvBuffer;
|
||||
out.flush(); // 确保数据立即写入磁盘,避免程序崩溃丢失数据
|
||||
outFile.close();
|
||||
//处理粒子数据
|
||||
changeUpdata(particles);
|
||||
//处理道址计数
|
||||
changeChannelParticleCount(particles);
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::changeUpdata(QList<ParticleData> &data)
|
||||
{
|
||||
QString dir = ProjectList::Instance()->GetCurrentProjectModel()->GetProjectDir();
|
||||
QString csvPath = QStringLiteral(u"%1/%2").arg(dir).arg("粒子数据.csv");
|
||||
auto dockList = _dock_manager->dockWidgetsMap().values();
|
||||
int i = 0;
|
||||
for(auto dock : dockList)
|
||||
{
|
||||
MeasureAnalysisView* view = dynamic_cast<MeasureAnalysisView*>(dock->widget());
|
||||
|
|
@ -636,26 +659,108 @@ void MainWindow::onGvfData(const QByteArray &data)
|
|||
&& view->GetViewType() == MeasureAnalysisView::DataTable)
|
||||
{
|
||||
MeasureAnalysisDataTableView* table = dynamic_cast<MeasureAnalysisDataTableView*>(view);
|
||||
table->RefreshTableData(csvPath);
|
||||
QString boardId = QString::number(data.at(i).boardId);
|
||||
QString channelId = QString::number(data.at(i).channelId);
|
||||
QString address = QString::number(data.at(i).address);
|
||||
QString timestampCount = QString::number(data.at(i).timestampCount);
|
||||
QStringList dataList;
|
||||
dataList << boardId << channelId << address << timestampCount;
|
||||
|
||||
ProjectList* project_list_model = ProjectList::Instance();
|
||||
auto project_model = project_list_model->GetCurrentProjectModel();
|
||||
const QString& all_channel_particle_data_filename = project_model->GetAllChannelParticleDataFilename();
|
||||
if (!all_channel_particle_data_filename.isEmpty()) {
|
||||
const QString& all_ch_count_dir = project_model->GetProjectDir();
|
||||
const QString& every_ch_count_dir = QDir(project_model->GetProjectDir()).filePath(QStringLiteral(u"通道道址计数"));
|
||||
auto count_task = new DataProcessWorkPool::EveryChannelParticleCountDataTask;
|
||||
count_task->SetAllChannelParticleDataFilename(all_channel_particle_data_filename);
|
||||
count_task->SetAllChannelCountResultDir(all_ch_count_dir);
|
||||
count_task->SetEveryChannelCountResultDir(every_ch_count_dir);
|
||||
count_task->SetFinishedNotifier(project_list_model, "onChannelAddressCountProcessFinished", project_model->GetProjectName());
|
||||
count_task->StartTask();
|
||||
}
|
||||
// initAction();
|
||||
// dataList << QString("%1,%2,%3,%4").arg(boardId).arg(channelId).arg(address).arg(timestampCount);
|
||||
table->AppendRow(dataList,false);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::changeChannelParticleCount(QList<ParticleData> &data)
|
||||
{
|
||||
bool ret_ok = true;
|
||||
|
||||
// 通道号 -> 地址 -> 计数
|
||||
for(auto info : data)
|
||||
{
|
||||
// 板卡和通道号计算,通道号 = 板卡号 * 4 + 通道号
|
||||
int channel_num = (info.boardId) * 4 + (info.channelId + 1);
|
||||
// 统计每个通道的粒子计数
|
||||
if (!channel_address_counts.contains(channel_num)) {
|
||||
channel_address_counts[channel_num] = QMap<uint, unsigned long long>();
|
||||
}
|
||||
channel_address_counts[channel_num][info.address]++;
|
||||
}
|
||||
|
||||
MeasureAnalysisProjectModel* models = ProjectList::Instance()->GetCurrentProjectModel();
|
||||
const QString& every_ch_count_dir = QDir(models->GetProjectDir()).filePath(QStringLiteral(u"通道道址计数"));
|
||||
QDir every_ch_count_output_dir(every_ch_count_dir);
|
||||
|
||||
// 写入每个通道的粒子计数数据(优化:使用一次打开文件,批量写入)
|
||||
QMap<uint, std::shared_ptr<std::ofstream>> channel_file_streams;
|
||||
// 预创建所有通道的文件流
|
||||
for (auto channel_it = channel_address_counts.begin(); channel_it != channel_address_counts.end(); ++channel_it) {
|
||||
uint channel_num = channel_it.key();
|
||||
QString count_data_filename = every_ch_count_output_dir.filePath(QStringLiteral(u"通道%1粒子计数.csv").arg(channel_num));
|
||||
particle_count_filename_list.insert(channel_num, count_data_filename);
|
||||
// 创建文件流
|
||||
std::shared_ptr<std::ofstream> out(new std::ofstream(QStrToSysPath(count_data_filename)));
|
||||
channel_file_streams[channel_num] = out;
|
||||
*out << QString(QStringLiteral(u"道址")).toStdString() << "," << QString(QStringLiteral(u"计数")).toStdString() << std::endl;
|
||||
}
|
||||
// 批量写入数据
|
||||
for (auto channel_it = channel_address_counts.begin(); channel_it != channel_address_counts.end(); ++channel_it) {
|
||||
uint channel_num = channel_it.key();
|
||||
const QMap<uint, unsigned long long>& address_counts = channel_it.value();
|
||||
auto out_stream = channel_file_streams[channel_num];
|
||||
for (auto address_it = address_counts.begin(); address_it != address_counts.end(); ++address_it) {
|
||||
uint address = address_it.key();
|
||||
unsigned long long count = address_it.value();
|
||||
*out_stream << address << "," << count << std::endl;
|
||||
}
|
||||
}
|
||||
channel_file_streams.clear();
|
||||
const QString& project_name = models->GetProjectName();
|
||||
MeasureAnalysisProjectModel* project_model = ProjectList::Instance()->GetProjectModel(project_name);
|
||||
if (project_model == nullptr) {
|
||||
ret_ok = false;
|
||||
} else {
|
||||
// 更新项目模型中的通道粒子计数数据文件名
|
||||
for (auto it = particle_count_filename_list.begin(); it != particle_count_filename_list.end(); ++it) {
|
||||
project_model->SetChannelAddressCountDataFilename(it.key(), it.value());
|
||||
}
|
||||
|
||||
QMap<QString, QMap<QString, QStandardItem *> > project_node_items = ProjectList::Instance()->getProjectNodeItems();
|
||||
QMap<QString, QStandardItem *> node_map = project_node_items[models->GetProjectName()];
|
||||
|
||||
const QString& adrr_count_item_name = QStringLiteral(u"道址计数");
|
||||
const QMap<uint, QString>& filename_list = models->GetChannelAddressCountDataFilenameList();
|
||||
bool status_ok = false;
|
||||
QString status = QStringLiteral(u"无效");
|
||||
if (!filename_list.isEmpty()) {
|
||||
status_ok = true;
|
||||
status = QStringLiteral(u"有效");
|
||||
}
|
||||
|
||||
if (node_map.contains(adrr_count_item_name)) {
|
||||
auto adrr_count_item = node_map[adrr_count_item_name];
|
||||
ProjectList::Instance()->SetNodeStatus(adrr_count_item, status, status_ok);
|
||||
for (auto it = filename_list.begin(); it != filename_list.end(); ++it) {
|
||||
uint ch_num = it.key();
|
||||
QString item_name = QStringLiteral(u"通道%1道址计数").arg(ch_num);
|
||||
if(node_map.contains(item_name))
|
||||
{
|
||||
return;
|
||||
}
|
||||
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_name, Qt::UserRole + 2);
|
||||
node_item->setData(ch_num, Qt::UserRole + 3);
|
||||
node_map[item_name] = node_item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::on_action_stop_measure_triggered()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <QMainWindow>
|
||||
#include <QMutex>
|
||||
#include "GvfToCsv/GvfToCsv.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui {
|
||||
|
|
@ -18,7 +19,6 @@ class MeasureAnalysisTreeView;
|
|||
class BackgroundTaskListView;
|
||||
class QPushButton;
|
||||
class MeasureClient;
|
||||
class GvfToCsv;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
|
|
@ -52,7 +52,10 @@ private:
|
|||
void initStatusBar();
|
||||
void applyStyleSheet();
|
||||
void closeProject(const QString &project_name);
|
||||
|
||||
//处理粒子数据
|
||||
void changeUpdata(QList<ParticleData> &data);
|
||||
//处理道址计数
|
||||
void changeChannelParticleCount(QList<ParticleData> &data);
|
||||
signals:
|
||||
void newProject(const QString &project_name);
|
||||
|
||||
|
|
@ -80,6 +83,7 @@ private slots:
|
|||
|
||||
void on_action_stop_measure_triggered();
|
||||
|
||||
|
||||
private:
|
||||
QMutex _mutex_info_output;
|
||||
QPlainTextEdit* _plain_edit_info_output;
|
||||
|
|
@ -100,5 +104,11 @@ private:
|
|||
QStringList deviceList;
|
||||
GvfToCsv *_gvfToCsv = nullptr;
|
||||
|
||||
|
||||
QMap<uint, QMap<uint, unsigned long long>> channel_address_counts; // 通道号 -> 地址 -> 计数
|
||||
QMap<uint, QString> particle_count_filename_list;
|
||||
|
||||
|
||||
|
||||
};
|
||||
#endif // MAINWINDOW_H
|
||||
|
|
|
|||
|
|
@ -5,6 +5,17 @@
|
|||
#include <QHBoxLayout>
|
||||
#include "GlobalDefine.h"
|
||||
|
||||
//2026-06-10
|
||||
static QString escapeCsvField(const QString& field)
|
||||
{
|
||||
if (field.contains(',') || field.contains('"') || field.contains('\n') || field.contains('\r')) {
|
||||
QString escaped = field;
|
||||
escaped.replace('"', "\"\"");
|
||||
return "\"" + escaped + "\"";
|
||||
}
|
||||
return field;
|
||||
}
|
||||
|
||||
MeasureAnalysisDataTableView::MeasureAnalysisDataTableView(QWidget* parent)
|
||||
: MeasureAnalysisView { parent }
|
||||
, _preload_policy(PreloadPolicy::Conservative)
|
||||
|
|
@ -36,16 +47,28 @@ void MeasureAnalysisDataTableView::SetAnalyzeDataFilename(const QMap<QString, QV
|
|||
if (data_files_set.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto csv_ddata_source = std::make_shared<CsvDataSource>(data_files_set.first().toString());
|
||||
if (!csv_ddata_source->isValid()) {
|
||||
return;
|
||||
}
|
||||
VirtualTableModel* table_model = new VirtualTableModel;
|
||||
table_model->setDataSource(csv_ddata_source);
|
||||
table_model->setPreloadPolicy(_preload_policy);
|
||||
table_model->setBlockSize(_block_size);
|
||||
|
||||
_tableView->setVirtualModel(table_model);
|
||||
//2026-06-10
|
||||
if (_tableModel) {
|
||||
_tableModel->deleteLater();
|
||||
}
|
||||
|
||||
_tableModel = new VirtualTableModel;
|
||||
_tableModel->setDataSource(csv_ddata_source);
|
||||
_tableModel->setPreloadPolicy(_preload_policy);
|
||||
_tableModel->setBlockSize(_block_size);
|
||||
|
||||
// VirtualTableModel* table_model = new VirtualTableModel;
|
||||
// table_model->setDataSource(csv_ddata_source);
|
||||
// table_model->setPreloadPolicy(_preload_policy);
|
||||
// table_model->setBlockSize(_block_size);
|
||||
|
||||
_tableView->setVirtualModel(_tableModel);
|
||||
_tableView->setBufferSize(_buffer_size);
|
||||
}
|
||||
|
||||
|
|
@ -54,10 +77,82 @@ void MeasureAnalysisDataTableView::RefreshTableData(const QString &csvFilePath)
|
|||
auto csv_source = std::make_shared<CsvDataSource>(csvFilePath);
|
||||
if(!csv_source->isValid()) return;
|
||||
|
||||
VirtualTableModel* newModel = new VirtualTableModel;
|
||||
newModel->setDataSource(csv_source);
|
||||
newModel->setPreloadPolicy(_preload_policy);
|
||||
newModel->setBlockSize(_block_size);
|
||||
_tableView->setVirtualModel(newModel);
|
||||
//2026-06-10
|
||||
if (_tableModel) {
|
||||
_tableModel->deleteLater();
|
||||
}
|
||||
|
||||
_tableModel = new VirtualTableModel;
|
||||
_tableModel->setDataSource(csv_source);
|
||||
_tableModel->setPreloadPolicy(_preload_policy);
|
||||
_tableModel->setBlockSize(_block_size);
|
||||
|
||||
// VirtualTableModel* newModel = new VirtualTableModel;
|
||||
// newModel->setDataSource(csv_source);
|
||||
// newModel->setPreloadPolicy(_preload_policy);
|
||||
// newModel->setBlockSize(_block_size);
|
||||
_tableView->setVirtualModel(_tableModel);
|
||||
_tableView->setBufferSize(_buffer_size);
|
||||
}
|
||||
|
||||
void MeasureAnalysisDataTableView::AppendRow(const QVariantList &rowData, bool writeToFile)
|
||||
{
|
||||
// 1. 前置校验
|
||||
if (!_tableModel || !_tableModel->dataSource()) {
|
||||
LOG_WARN(QStringLiteral(u"追加行失败:表格模型或数据源未初始化"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto dataSource = std::dynamic_pointer_cast<CsvDataSource>(_tableModel->dataSource());
|
||||
if (!dataSource || !dataSource->isValid()) {
|
||||
LOG_WARN(QStringLiteral(u"追加行失败:CSV数据源无效"));
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 列数匹配
|
||||
const int expectedColumns = _tableModel->columnCount();
|
||||
if (rowData.size() != expectedColumns) {
|
||||
LOG_WARN(QStringLiteral(u"追加行失败:列数不匹配,期望%1列,实际%2列")
|
||||
.arg(expectedColumns).arg(rowData.size()));
|
||||
return;
|
||||
}
|
||||
//需要写入文件的
|
||||
if (writeToFile) {
|
||||
QFile file(dataSource->filePath());
|
||||
QTextStream out(&file);
|
||||
out.setCodec("UTF-8"); // 与读取时的 QString::fromUtf8 保持一致
|
||||
|
||||
QStringList escapedFields;
|
||||
for (const QVariant& field : rowData) {
|
||||
escapedFields.append(escapeCsvField(field.toString()));
|
||||
}
|
||||
|
||||
out << escapedFields.join(',') << "\n";
|
||||
file.close();
|
||||
LOG_DEBUG(QStringLiteral(u"已成功将新行写入CSV文件:%1").arg(dataSource->filePath()));
|
||||
RefreshTableData(dataSource->filePath());
|
||||
return;
|
||||
}
|
||||
|
||||
QFile file(dataSource->filePath());
|
||||
if (!file.open(QIODevice::Append | QIODevice::Text)) {
|
||||
LOG_ERROR(QStringLiteral(u"追加行失败:无法打开文件 %1,错误:%2")
|
||||
.arg(file.fileName()).arg(file.errorString()));
|
||||
return;
|
||||
}
|
||||
|
||||
// 4. 重新加载整个表格,确保模型与文件同步
|
||||
RefreshTableData(dataSource->filePath());
|
||||
|
||||
// 5. 自动滚动到底部
|
||||
_tableView->scrollToBottom();
|
||||
}
|
||||
|
||||
void MeasureAnalysisDataTableView::AppendRow(const QStringList &rowData, bool writeToFile)
|
||||
{
|
||||
QVariantList varList;
|
||||
for (const QString& field : rowData) {
|
||||
varList.append(QVariant(field));
|
||||
}
|
||||
AppendRow(varList, writeToFile);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,12 +21,19 @@ public:
|
|||
virtual void SetAnalyzeDataFilename(const QMap<QString, QVariant>& data_files_set);
|
||||
void RefreshTableData(const QString& csvFilePath);
|
||||
|
||||
|
||||
// 2026-06-10 表尾插入数据函数(支持两种参数类型,默认同时写入CSV文件)
|
||||
void AppendRow(const QVariantList& rowData, bool writeToFile = true);
|
||||
void AppendRow(const QStringList& rowData, bool writeToFile = true);
|
||||
private:
|
||||
// 私有成员变量
|
||||
VirtualTableView *_tableView;
|
||||
PreloadPolicy _preload_policy; // 预加载策略
|
||||
uint _block_size; // 块大小输入框
|
||||
uint _buffer_size; // 缓冲区大小输入框
|
||||
//2026-06-10
|
||||
VirtualTableModel* _tableModel = nullptr; // 持有模型指针,避免内存泄漏
|
||||
|
||||
};
|
||||
|
||||
#endif // MEASUREANALYSISDATATABLEVIEW_H
|
||||
|
|
|
|||
|
|
@ -111,6 +111,11 @@ QVariant VirtualTableModel::headerData(int section, Qt::Orientation orientation,
|
|||
return QVariant();
|
||||
}
|
||||
|
||||
std::shared_ptr<DataSource> VirtualTableModel::dataSource() const
|
||||
{
|
||||
return m_dataSource;
|
||||
}
|
||||
|
||||
void VirtualTableModel::setDataSource(std::shared_ptr<DataSource> source)
|
||||
{
|
||||
beginResetModel();
|
||||
|
|
|
|||
|
|
@ -64,6 +64,10 @@ public:
|
|||
QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const override;
|
||||
|
||||
//2026-06-10
|
||||
std::shared_ptr<DataSource> dataSource() const;
|
||||
|
||||
|
||||
// 公共接口方法
|
||||
/**
|
||||
* @brief 设置数据源
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user