EnergySpectrumAnalyer/src/MainWindow.cpp
2026-06-03 18:09:39 +08:00

620 lines
25 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QAction>
#include <QDateTime>
#include <QDir>
#include <QHBoxLayout>
#include <QLabel>
#include <QMenu>
#include <QPlainTextEdit>
#include <QScrollBar>
#include <QFileDialog>
#include <QMessageBox>
#include "DockAreaWidget.h"
#include "DockComponentsFactory.h"
#include "DockManager.h"
#include "DockWidget.h"
#include "FloatingDockContainer.h"
#include "AboutDlg.h"
#include "DataProcessWorkPool.h"
#include "EnergyScaleForm.h"
#include "MeasureAnalysisHistoryForm.h"
#include "MeasureAnalysisProjectModel.h"
#include "NewMeasureAnalysisDlg.h"
#include "MeasureAnalysisView.h"
#include "MeasureAnalysisTreeView.h"
#include "GlobalDefine.h"
#include "DeviceParamsManagerDlg.h"
#include "NuclideLib.h"
#include "BackgroundTaskListView.h"
#include <QDesktopWidget>
#include <QJsonDocument>
#include <QJsonObject>
#include "MeasureClient.h"
#include "GvfToCsv/GvfToCsv.h"
using namespace ads;
MainWindow* MainWindow::_s_main_win = nullptr;
void MainWindow::OutputInfo(OutputInfoType out_type, const QString& ouput_info)
{
QMetaObject::invokeMethod(_s_main_win, "onOutputInfo", Qt::QueuedConnection, Q_ARG(int, int(out_type)), Q_ARG(QString, ouput_info));
}
void MainWindow::ShowStatusBarMsg(const QString& msg)
{
QMetaObject::invokeMethod(_s_main_win, "onShowStatusBarMsg", Qt::QueuedConnection, Q_ARG(QString, msg));
}
void MainWindow::onOutputInfo(int out_type, const QString &ouput_info)
{
if (!ouput_info.isEmpty()) {
QStringList list_str_out_type = {
QStringLiteral(u"信息"),
QStringLiteral(u"警告"),
QStringLiteral(u"错误"),
QStringLiteral(u"调试")
};
QList<QColor> list_color_out_type = {
Qt::black,
Qt::darkYellow,
Qt::red,
Qt::darkBlue
};
const QString& ouput_text = QString("%1 [%2] : %3")
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
.arg(list_str_out_type.at(int(out_type)))
.arg(ouput_info);
QTextCharFormat cur_fmt, fmt;
fmt.setForeground(QBrush(list_color_out_type.at(out_type)));
_mutex_info_output.lock();
cur_fmt = _plain_edit_info_output->currentCharFormat();
_plain_edit_info_output->mergeCurrentCharFormat(fmt);
_plain_edit_info_output->appendPlainText(ouput_text);
_plain_edit_info_output->setCurrentCharFormat(cur_fmt);
QScrollBar* scrollbar = _plain_edit_info_output->verticalScrollBar();
if (scrollbar) {
scrollbar->setSliderPosition(scrollbar->maximum());
}
_plain_edit_info_output->update();
_mutex_info_output.unlock();
}
}
void MainWindow::onShowStatusBarMsg(const QString &msg)
{
_status_bar->showMessage(msg);
}
MainWindow::MainWindow(QWidget* parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
_status_bar = ui->statusbar;
_gvfToCsv = new GvfToCsv;
_measure_client = new MeasureClient;
connect(_measure_client, &MeasureClient::getDeviceListResult, this, &MainWindow::onGetDeviceListResult);
connect(_measure_client, &MeasureClient::startMeasureResult, this, &MainWindow::onStartMeasureResult);
connect(_measure_client, &MeasureClient::stopMeasureResult, this, &MainWindow::onStopMeasureResult);
connect(_measure_client, &MeasureClient::setMeasureConfigParamsResult, this, &MainWindow::onSetMeasureConfigParamsResult);
connect(_measure_client, &MeasureClient::clearDataResult, this, &MainWindow::onClearDataResult);
connect(_measure_client, &MeasureClient::runningInfo, this, &MainWindow::onRunningInfo);
connect(_measure_client, &MeasureClient::errorOccurred, this, &MainWindow::onErrorOccurred);
connect(_measure_client, &MeasureClient::gvfData, this, &MainWindow::onGvfData);
_measure_client->connectToServer();
initMainWindow();
initAction();
initStatusBar();
this->applyStyleSheet();
_s_main_win = this;
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::initMainWindow()
{
ads::CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true);
ads::CDockManager::setConfigFlag(ads::CDockManager::DockAreaHasCloseButton, true);
ads::CDockManager::setConfigFlag(ads::CDockManager::AllTabsHaveCloseButton, true);
ads::CDockManager::setConfigFlag(ads::CDockManager::DockAreaHasUndockButton, true);
ads::CDockManager::setConfigFlag(ads::CDockManager::DockAreaDynamicTabsMenuButtonVisibility, true);
ads::CDockManager::setConfigFlag(ads::CDockManager::DisableTabTextEliding, true);
ads::CDockManager::setConfigFlag(ads::CDockManager::DoubleClickUndocksWidget, false);
ads::CDockManager::setAutoHideConfigFlags({ CDockManager::DefaultAutoHideConfig });
_dock_manager = new CDockManager(this);
_dock_manager->setFrameStyle(QFrame::StyledPanel | QFrame::Plain);
_dock_manager->setLineWidth(1);
// Set central widget
MeasureAnalysisHistoryForm* measure_analysis_history_form = new MeasureAnalysisHistoryForm;
connect(this, &MainWindow::newProject, measure_analysis_history_form, &MeasureAnalysisHistoryForm::onUpdateNewHistoryProject);
CDockWidget* central_dock_widget = _dock_manager->createDockWidget(QStringLiteral(u"测量分析记录"));
central_dock_widget->setWidget(measure_analysis_history_form);
// central_dock_widget->setFeature(ads::CDockWidget::AllDockWidgetFeatures, true);
_central_dock_area = _dock_manager->setCentralWidget(central_dock_widget);
_action_central_dock_widget = central_dock_widget->toggleViewAction();
// _action_central_dock_widget->setCheckable(false);
ui->menu_view->addAction(_action_central_dock_widget);
// 构建测量分析工程树视图
_tree_measure_analysis = new MeasureAnalysisTreeView;
_dockw_measure_analysis_tree = new ads::CDockWidget(QStringLiteral(u"测量分析工作空间"));
_dockw_measure_analysis_tree->setWidget(_tree_measure_analysis);
_dockw_measure_analysis_tree->setMinimumSizeHintMode(ads::CDockWidget::MinimumSizeHintFromContent);
_dock_manager->addDockWidget(ads::DockWidgetArea::LeftDockWidgetArea, _dockw_measure_analysis_tree);
ui->menu_view->addAction(_dockw_measure_analysis_tree->toggleViewAction());
_menu_view_data_table_list = ui->menu_view->addMenu(QStringLiteral(u"查看数据列表"));
_menu_view_analysis_view_list = ui->menu_view->addMenu(QStringLiteral(u"分析视图列表"));
// 构建日志输出视图
_plain_edit_info_output = new QPlainTextEdit;
_plain_edit_info_output->setReadOnly(true);
_plain_edit_info_output->setFrameShape(QFrame::NoFrame);
_plain_edit_info_output->setLineWidth(0);
ads::CDockWidget* dockw_info_output = new ads::CDockWidget(QStringLiteral(u"信息输出"));
dockw_info_output->setWidget(_plain_edit_info_output);
dockw_info_output->setMinimumSizeHintMode(ads::CDockWidget::MinimumSizeHintFromContent);
_dock_manager->addDockWidget(ads::DockWidgetArea::BottomDockWidgetArea, dockw_info_output);
ui->menu_view->addAction(dockw_info_output->toggleViewAction());
}
void MainWindow::initAction()
{
auto new_measurement_analysis_handler = [this]() {
NewMeasureAnalysisDlg new_measure_analysis_dlg;
if (QDialog::Accepted == new_measure_analysis_dlg.exec()) {
ProjectList* project_list_model = ProjectList::Instance();
auto project_model = project_list_model->GetCurrentProjectModel();
emit newProject(project_model->GetProjectName());
if (project_model->GetIsMeasureComplete()) {
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();
auto coincidence_process_task = new DataProcessWorkPool::CoincidenceEventAnalysisTask;
coincidence_process_task->SetFinishedNotifier(project_list_model, "onCoincidenceProcessFinished", project_model->GetProjectName());
coincidence_process_task->StartTask();
}
} else {
}
}
};
connect(ui->action_new_measurement_analysis, &QAction::triggered, new_measurement_analysis_handler);
connect(ui->action_open_measurement_analysis, &QAction::triggered, [this](){
const QString& filename = QFileDialog::getOpenFileName(this, QStringLiteral(u"选择测量分析项目文件"), QString(), QStringLiteral(u"测量分析项目 (*.msproject)"));
if (filename.isEmpty()) {
return;
}
QFileInfo file_info(filename);
if (file_info.size() == 0) {
QMessageBox::warning(this, QStringLiteral(u"警告"), QStringLiteral(u"选择的测量分析项目文件为空文件!"));
return;
}
MeasureAnalysisProjectModel* model = new MeasureAnalysisProjectModel;
if (model->LoadProjectModel(filename)) {
ProjectList::Instance()->AddProjectModel(model);
}
});
connect(ui->action_save_measurement_analysis, &QAction::triggered, [](){
MeasureAnalysisProjectModel* project_model = ProjectList::Instance()->GetCurrentProjectModel();
if (project_model) {
const QString& project_name = project_model->GetProjectName();
if ( project_model->SaveProjectModel() ){
const QString& info_text = QStringLiteral(u"保存测量分析项目\"%1\"完成.").arg(project_name);
LOG_INFO(info_text);
} else {
const QString& warn_text = QStringLiteral(u"保存测量分析项目\"%1\"失败!").arg(project_name);
LOG_WARN(warn_text);
}
}
});
connect(ui->action_close_measurement_analysis, &QAction::triggered, [this](){
MeasureAnalysisProjectModel* project_model = ProjectList::Instance()->GetCurrentProjectModel();
if (project_model) {
const QString& project_name = project_model->GetProjectName();
const QString& title = QStringLiteral(u"关闭测量分析项目");
const QString& text = QStringLiteral(u"是否关闭测量分析项目\"%1\"").arg(project_name);
auto result = QMessageBox::question(this, title, text, QMessageBox::Yes | QMessageBox::No);
if (QMessageBox::Yes == result) {
this->closeProject(project_name);
}
}
});
connect(ui->action_manage_measurement_analysis, &QAction::triggered, [this](){
this->_action_central_dock_widget->triggered(true);
});
connect(ui->action_device_config_mrg, &QAction::triggered, []() {
DeviceParamsManagerDlg().exec();
});
connect(ui->action_energy_scale_mrg, &QAction::triggered, []() {
QDialog energy_scale_mrg_dlg;
energy_scale_mrg_dlg.setObjectName("EnergyScaleFormDlg");
energy_scale_mrg_dlg.setWindowTitle(QStringLiteral(u"能量刻度管理"));
energy_scale_mrg_dlg.setWindowFlags(energy_scale_mrg_dlg.windowFlags() | Qt::WindowMaximizeButtonHint);
EnergyScaleForm* energy_scale_mrg_form = new EnergyScaleForm(&energy_scale_mrg_dlg);
QHBoxLayout* hlayout = new QHBoxLayout;
hlayout->addWidget(energy_scale_mrg_form);
energy_scale_mrg_dlg.setLayout(hlayout);
energy_scale_mrg_dlg.exec();
});
connect(ui->action_about_info, &QAction::triggered, []() {
AboutDlg about_dlg;
about_dlg.exec();
});
connect(_tree_measure_analysis, &MeasureAnalysisTreeView::currentItemView, [this](MeasureAnalysisView* view) {
if (view && this->_dock_manager) {
bool view_exist = false;
QList<CDockWidget*> dock_widget_list = this->_dock_manager->dockWidgetsMap().values();
for (auto it = dock_widget_list.constBegin(); it != dock_widget_list.constEnd(); ++it) {
CDockWidget* dock_widget = *it;
if (dock_widget) {
MeasureAnalysisView* dock_view = dynamic_cast<MeasureAnalysisView*>(dock_widget->widget());
if ( dock_view ) {
if (dock_view->GetViewName() == view->GetViewName()) {
dock_widget->toggleView();
dock_widget->raise();
view_exist = true;
}
}
}
}
if ( !view_exist ) {
ads::CDockWidget* dock_widget = new ads::CDockWidget(view->GetViewName());
view->setMinimumSize(320, 280);
dock_widget->setWidget(view);
dock_widget->setMinimumSizeHintMode(ads::CDockWidget::MinimumSizeHintFromContent);
if (view->IsDeleteOnClose()) {
// dock_widget->setFeatures(dock_widget->features() | ads::CDockWidget::DockWidgetDeleteOnClose);
dock_widget->setFeatures(dock_widget->features() | ads::CDockWidget::CustomCloseHandling);
connect(dock_widget, &CDockWidget::closeRequested, [this, dock_widget, view](){
MeasureAnalysisView* dock_view = dynamic_cast<MeasureAnalysisView*>(dock_widget->widget());
if ( dock_view ) {
const QString& view_name = view->GetViewName();
if (dock_view->GetViewName() == view_name) {
_tree_measure_analysis->RemoveItemView(view_name);
}
}
});
}
if ( view->GetViewType() == MeasureAnalysisView::DataTable ) {
_menu_view_data_table_list->addAction(dock_widget->toggleViewAction());
}
if ( view->GetViewType() == MeasureAnalysisView::PlotFrame ) {
_menu_view_analysis_view_list->addAction(dock_widget->toggleViewAction());
}
auto central_area = _dock_manager->centralWidget()->dockAreaWidget();
_dock_manager->addDockWidget(ads::DockWidgetArea::CenterDockWidgetArea, dock_widget, central_area);
}
}
});
connect(_tree_measure_analysis, &MeasureAnalysisTreeView::removeItemView, [this](MeasureAnalysisView* view) {
if (this->_dock_manager) {
QList<CDockWidget*> dock_widget_list = this->_dock_manager->dockWidgetsMap().values();
for (auto it = dock_widget_list.constBegin(); it != dock_widget_list.constEnd(); ++it) {
CDockWidget* dock_widget = *it;
if (dock_widget) {
if ( dock_widget->widget() == view ) {
dock_widget->deleteDockWidget();
}
}
}
}
});
}
void MainWindow::initStatusBar()
{
_w_watcher_task_list = new BackgroundTaskListView(this);
_btn_task_watcher = new QPushButton(QStringLiteral(u"后台任务监视"), _status_bar);
_status_bar->addPermanentWidget(_btn_task_watcher);
connect(_btn_task_watcher, &QPushButton::clicked, this, [this](){
if ( _w_watcher_task_list->isVisible() ) {
_w_watcher_task_list->hide();
} else {
this->onShowBackgroundTaskList();
}
});
}
void MainWindow::applyStyleSheet()
{
// #ifdef ENABLE_DEBUG
// QString style_file_path = "D:/Workspace/EnergySpectrumAnalyerProject/EnergySpectrumAnalyer/style/stylesheet/";
// #else
QString style_file_path = ":/stylesheet/";
// #endif
QFile file_stylesheet_default(style_file_path + "default.qss");
if (file_stylesheet_default.open(QFile::ReadOnly)) {
const QString& str_stylesheet_default = file_stylesheet_default.readAll();
qApp->setStyleSheet(str_stylesheet_default);
}
QFile file_stylesheet_dock(style_file_path + "dock.qss");
if (file_stylesheet_dock.open(QFile::ReadOnly)) {
const QString& str_stylesheet_dock = file_stylesheet_dock.readAll();
_dock_manager->setStyleSheet(_dock_manager->styleSheet() + str_stylesheet_dock);
}
}
void MainWindow::closeProject(const QString& project_name)
{
auto closeAnalysisView = [this](const QString& project_name){
if (this->_dock_manager) {
QList<CDockWidget*> dock_widget_list = this->_dock_manager->dockWidgetsMap().values();
for (auto it = dock_widget_list.constBegin(); it != dock_widget_list.constEnd(); ++it) {
CDockWidget* dock_widget = *it;
if (dock_widget) {
MeasureAnalysisView* view = dynamic_cast<MeasureAnalysisView*>(dock_widget->widget());
if (view ) {
if ( view->GetProjectName() == project_name ) {
dock_widget->deleteDockWidget();
}
}
}
}
}
};
MeasureAnalysisProjectModel* project_model = ProjectList::Instance()->GetProjectModel(project_name);
if (project_model) {
closeAnalysisView(project_name);
project_model->SaveProjectModel();
if(ProjectList::Instance()->RmProjectModel(project_name)) {
const QString& info_text = QStringLiteral(u"测试分析项\"%1\"已关闭.").arg(project_name);
LOG_INFO(info_text);
}
}
}
void MainWindow::showEvent(QShowEvent *event)
{
QMainWindow::showEvent(event);
this->applyStyleSheet();
}
void MainWindow::closeEvent(QCloseEvent* event)
{
QList<MeasureAnalysisProjectModel *> models = ProjectList::Instance()->GetProjectModels();
for (auto model : models) {
if (model) {
closeProject(model->GetProjectName());
}
}
QMainWindow::closeEvent(event);
}
void MainWindow::moveEvent(QMoveEvent *event)
{
QMainWindow::moveEvent(event);
if (this->_w_watcher_task_list->isVisible()) {
onShowBackgroundTaskList();
}
}
void MainWindow::on_action_nuclideLib_triggered()
{
NuclideLibManage *nuclidelib = new NuclideLibManage();
nuclidelib->show();
}
void MainWindow::onShowBackgroundTaskList()
{
this->updateGeometry();
this->_btn_task_watcher->updateGeometry();
this->_w_watcher_task_list->adjustSize();
QSize pop_size = this->_w_watcher_task_list->size();
QPoint btn_top_teft = this->_btn_task_watcher->mapToGlobal(QPoint(0, 0));
int btn_width = this->_btn_task_watcher->width();
// int btn_height = this->_btn_task_watcher->height();
int x = btn_top_teft.x() + btn_width - pop_size.width() - 2;
int y = btn_top_teft.y() - pop_size.height() - 6;
// QRect screen_rect = QApplication::desktop()->availableGeometry(this);
// if (x < screen_rect.left() + 6)
// x = screen_rect.left();
// if (x + pop_size.width() > screen_rect.right())
// x = screen_rect.right() - pop_size.width();
// if (y < screen_rect.top())
// y = btn_top_teft.y() + btn_height + 6;
this->_w_watcher_task_list->move(x, y);
this->_w_watcher_task_list->show();
}
void MainWindow::resizeEvent(QResizeEvent *event)
{
QMainWindow::resizeEvent(event);
if (this->_w_watcher_task_list->isVisible()) {
onShowBackgroundTaskList();
}
}
void MainWindow::on_action_start_measure_triggered()
{
LOG_INFO(QStringLiteral(u"查找测量设备... ..."));
_measure_client->getDeviceList();
LOG_INFO(QStringLiteral(u"开始测量... ..."));
QString device_guid;
if(deviceList.size()>0)
{
device_guid = deviceList.at(0);
}
MeasureAnalysisProjectModel* models = ProjectList::Instance()->GetCurrentProjectModel();
QMap<QString, QMap<QString, QStandardItem *> > project_node_items = ProjectList::Instance()->getProjectNodeItems();
QMap<QString, QStandardItem *> node = project_node_items[models->GetProjectName()];
QStandardItem *nodeItem = node[models->GetProjectName()];
ProjectList::Instance()->SetNodeStatus(nodeItem,"测量中",true);
QString projectName;
QString deviceCfg;
if(models)
{
projectName = models->GetProjectName();
deviceCfg = models->GetMeasureDeviceParamsCfgFilename();
if(deviceCfg == "")
{
QMessageBox::information(this,"提示","设备参数配置未配置","确认","取消");
}
}
QFile json_file(deviceCfg);
if (!json_file.open(QIODevice::ReadOnly | QIODevice::Text)) {
LOG_INFO(QStringLiteral(u"加载设备参数配置失败:%1").arg(deviceCfg));
return;
}
QByteArray json_data = json_file.readAll();
json_file.close();
QJsonDocument json_doc = QJsonDocument::fromJson(json_data);
if (json_doc.isNull()) {
return;
}
if (!json_doc.isObject())
return;
QVariantMap device_config_info = json_doc.object().toVariantMap();
if (!device_config_info.contains(QStringLiteral(u"ChannelConfig")))
return;
QVariantList channel_config_list = device_config_info[QStringLiteral(u"ChannelConfig")].toList();
if (channel_config_list.isEmpty()) {
LOG_INFO(QStringLiteral(u"测量设备通道配置参数为空."));
return;
}
_measure_client->startMeasure(device_guid, device_config_info);
}
void MainWindow::onStartMeasureResult(bool success, const QString &info)
{
if(success)
{
LOG_INFO(QStringLiteral(u"启动测量成功"));
LOG_INFO(QStringLiteral(u"测量数据GVF文件: %1").arg(info));
}
else
LOG_INFO(QStringLiteral(u"启动测量失败: %1").arg(info));
}
void MainWindow::onStopMeasureResult(bool success, const QString &message)
{
if(success){
LOG_INFO(QStringLiteral(u"停止测量成功"));
}
else
LOG_INFO(QStringLiteral(u"停止测量失败: %1").arg(message));
}
void MainWindow::onSetMeasureConfigParamsResult(bool success, const QString &message)
{
if(success){
LOG_INFO(QStringLiteral(u"设置测量参数成功"));
}
else
LOG_INFO(QStringLiteral(u"设置测量参数失败: %1").arg(message));
}
void MainWindow::onClearDataResult(bool success, const QString &message)
{
if(success){
LOG_INFO(QStringLiteral(u"清除测量数据成功"));
}
else
LOG_INFO(QStringLiteral(u"清除测量数据失败: %1").arg(message));
}
void MainWindow::onGetDeviceListResult(bool success, const QString &message, const QStringList &devices)
{
if (success) {
deviceList = devices;
}
//测试
deviceList.append("0x01");
}
void MainWindow::onErrorOccurred(const QString &error_string)
{
LOG_INFO(QStringLiteral(u"错误: %1").arg(error_string));
}
void MainWindow::onRunningInfo(const QString &run_info)
{
LOG_INFO(QStringLiteral(u"信息: %1").arg(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"));
return;
}
QString dir = ProjectList::Instance()->GetCurrentProjectModel()->GetProjectDir();
QString csvPath = QStringLiteral(u"%1/%2").arg(dir).arg("粒子数据.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");
LOG_INFO(QStringLiteral(u"CSV文件为空已自动写入表头: %1").arg(csvPath));
}
QString csvBuffer;
csvBuffer.reserve(particles.size() * 64); // 单条数据约64字节预分配足够内存
for (const auto &p : particles) {
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();
LOG_INFO(QStringLiteral(u"已成功追加写入%1条粒子数据到CSV文件: %2")
.arg(particles.size())
.arg(csvPath));
}
void MainWindow::on_action_stop_measure_triggered()
{
const QString& device_guid = deviceList.at(0);
if (device_guid.isEmpty()) {
LOG_INFO(QStringLiteral(u"未选择测量设备GUID."));
return;
}
_measure_client->stopMeasure(device_guid);
}