#include "mainwindow.h" #include "ui_mainwindow.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "VrLog.h" #include "VrDateUtils.h" #include #include #include #include #include #include #include #include #include #include #include "TunnelChannelPresenter.h" #include "Version.h" #include "IVrUtils.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) , m_selectedButton(nullptr) , m_contextMenu(nullptr) , m_saveDataAction(nullptr) { ui->setupUi(this); // 设置窗口图标(Windows使用.ico格式) #ifdef _WIN32 this->setWindowIcon(QIcon(":/common/resource/logo.ico")); #else this->setWindowIcon(QIcon(":/common/resource/logo.png")); #endif // 设置状态栏字体 QFont statusFont = statusBar()->font(); statusFont.setPointSize(12); statusBar()->setFont(statusFont); // 设置状态栏颜色和padding statusBar()->setStyleSheet("QStatusBar { color: rgb(239, 241, 245); padding: 20px; }"); // 在状态栏右侧添加版本信息(包含编译时间) QString versionWithBuildTime = QString("%1_%2%3%4%5%6%7") .arg(GetTunnelChannelFullVersion()) .arg(YEAR) .arg(MONTH, 2, 10, QChar('0')) .arg(DAY, 2, 10, QChar('0')) .arg(HOUR, 2, 10, QChar('0')) .arg(MINUTE, 2, 10, QChar('0')) .arg(SECOND, 2, 10, QChar('0')); QLabel* buildLabel = new QLabel(versionWithBuildTime); buildLabel->setStyleSheet("color: rgb(239, 241, 245); font-size: 20px; margin-right: 16px;"); statusBar()->addPermanentWidget(buildLabel); // 隐藏标题栏 setWindowFlags(Qt::FramelessWindowHint); // 启动后自动最大化显示 this->showMaximized(); // 初始化时隐藏label_work ui->label_work->setVisible(false); // 初始化3D图像视图的GraphicsScene QGraphicsScene* scene3d = new QGraphicsScene(this); ui->detect_image_3d->setScene(scene3d); // 初始化2D图像视图的GraphicsScene QGraphicsScene* scene2d = new QGraphicsScene(this); ui->detect_image_2d->setScene(scene2d); // 初始化日志模型 m_logModel = new QStringListModel(this); ui->detect_log->setModel(m_logModel); // 注册自定义类型,使其能够在信号槽中跨线程传递 qRegisterMetaType("TunnelDetectionResult"); qRegisterMetaType("WorkStatus"); qRegisterMetaType("TunnelPosition"); // 连接工作状态更新信号槽 connect(this, &MainWindow::workStatusUpdateRequested, this, &MainWindow::updateWorkStatusLabel); // 连接检测结果更新信号槽 connect(this, &MainWindow::detectionResultUpdateRequested, this, &MainWindow::updateDetectionResultDisplay); // 连接日志更新信号槽 connect(this, &MainWindow::logUpdateRequested, this, &MainWindow::updateDetectionLog); // 连接清空日志信号槽 connect(this, &MainWindow::logClearRequested, this, &MainWindow::clearDetectionLogUI); // 连接2D图像更新信号槽 connect(this, &MainWindow::hikImageUpdateRequested, this, &MainWindow::updateHikImageDisplay); // 初始化右键菜单 setupContextMenu(); // 初始化补光灯按钮 setupSupplementLightButton(); updateStatusLog(tr("设备开始初始化...")); // 初始化模块 Init(); } MainWindow::~MainWindow() { // 释放业务逻辑处理类 if (m_presenter) { delete m_presenter; m_presenter = nullptr; } delete ui; } void MainWindow::updateStatusLog(const QString& message) { // 通过信号槽机制更新detect_log控件 emit logUpdateRequested(message); } void MainWindow::clearDetectionLog() { // 通过信号槽机制清空日志 emit logClearRequested(); } void MainWindow::Init() { // 创建业务逻辑处理类 m_presenter = new TunnelChannelPresenter(); // 设置状态回调接口(使用BasePresenter的模板方法) m_presenter->SetStatusCallback(this); // 设置海康相机显示窗口句柄(使用 QGraphicsView 的 viewport 进行硬件渲染) // viewport() 返回内部用于显示的 QWidget,适合作为海康SDK的渲染目标 m_presenter->SetHikDisplayWindow((void*)ui->detect_image_2d->viewport()->winId()); m_deviceStatusWidget = new DeviceStatusWidget(); // 连接DeviceStatusWidget的相机点击信号到MainWindow的槽函数 connect(m_deviceStatusWidget, SIGNAL(cameraClicked(int)), this, SLOT(onCameraClicked(int))); // 将设备状态widget添加到frame_dev中 QVBoxLayout* frameDevLayout = new QVBoxLayout(ui->frame_dev); frameDevLayout->setContentsMargins(0, 0, 0, 0); frameDevLayout->addWidget(m_deviceStatusWidget); // 设置列表视图模式(双相机布局配置) ui->detect_result_list->setViewMode(QListView::IconMode); ui->detect_result_list->setResizeMode(QListView::Adjust); ui->detect_result_list->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); ui->detect_result_list->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // 设置网格大小(双相机布局) int gridWidth = 230; int gridHeight = 190; ui->detect_result_list->setGridSize(QSize(gridWidth, gridHeight)); // 设置默认相机数量为2(3D相机 + 海康2D相机) m_deviceStatusWidget->setCameraCount(2); m_deviceStatusWidget->setCamera1Name(tr("3D相机")); m_deviceStatusWidget->setCamera2Name(tr("2D相机")); // 初始化期间禁用所有功能按钮 setButtonsEnabled(false); #if 1 // 在线程中执行初始化业务逻辑 std::thread initThread([this]() { updateStatusLog(tr("正在初始化系统...")); int result = m_presenter->Init(); if (result != 0) { updateStatusLog(tr("初始化失败,错误码:%1").arg(result)); } else { updateStatusLog(tr("系统初始化完成")); } }); // 分离线程,让其在后台运行 initThread.detach(); #endif } void MainWindow::display3DImage(const QImage& image) { if (image.isNull()) { updateStatusLog(tr("3D图片无效")); return; } QGraphicsScene* scene = ui->detect_image_3d->scene(); scene->clear(); QPixmap pixmap = QPixmap::fromImage(image); scene->addPixmap(pixmap); ui->detect_image_3d->fitInView(scene->sceneRect(), Qt::KeepAspectRatio); } void MainWindow::display2DImage(const QImage& image) { if (image.isNull()) { updateStatusLog(tr("2D图片无效")); return; } QGraphicsScene* scene = ui->detect_image_2d->scene(); scene->clear(); QPixmap pixmap = QPixmap::fromImage(image); scene->addPixmap(pixmap); ui->detect_image_2d->fitInView(scene->sceneRect(), Qt::KeepAspectRatio); } void MainWindow::addDetectionResult(const TunnelDetectionResult& result) { // 清空之前的所有检测结果数据 ui->detect_result_list->clear(); // 添加检测结果信息 QWidget* resultWidget = new QWidget(); resultWidget->setAutoFillBackground(true); QVBoxLayout* layout = new QVBoxLayout(resultWidget); layout->setContentsMargins(10, 10, 10, 10); QLabel* titleLabel = new QLabel("检测结果"); titleLabel->setStyleSheet("color: rgb(239, 241, 245); font-weight: bold; font-size: 14pt;"); layout->addWidget(titleLabel); QLabel* typeLabel = new QLabel(QString("检测类型: %1").arg(result.detectionType == 0 ? "正常" : "异常")); QLabel* confidenceLabel = new QLabel(QString("置信度: %1%").arg(result.confidence * 100, 0, 'f', 2)); QLabel* statusLabel = new QLabel(QString("状态: %1").arg(0 == result.errorCode ? "成功" : "失败")); typeLabel->setStyleSheet("color: rgb(239, 241, 245); font-size: 12pt;"); confidenceLabel->setStyleSheet("color: rgb(239, 241, 245); font-size: 12pt;"); statusLabel->setStyleSheet("color: rgb(239, 241, 245); font-size: 12pt;"); layout->addWidget(typeLabel); layout->addWidget(confidenceLabel); layout->addWidget(statusLabel); if (!result.alarmMessage.empty()) { QLabel* alarmLabel = new QLabel(QString("报警: %1").arg(QString::fromStdString(result.alarmMessage))); alarmLabel->setStyleSheet("color: rgb(255, 100, 100); font-size: 12pt;"); layout->addWidget(alarmLabel); } resultWidget->setStyleSheet("background-color: rgb(37, 38, 42); border: 1px solid #191A1C;"); QListWidgetItem* item = new QListWidgetItem(); item->setBackground(QBrush(Qt::transparent)); item->setSizeHint(QSize(280, 150)); item->setFlags(item->flags() & ~Qt::ItemIsDragEnabled & ~Qt::ItemIsDropEnabled); ui->detect_result_list->addItem(item); ui->detect_result_list->setItemWidget(item, resultWidget); } // 状态更新槽函数 void MainWindow::OnStatusUpdate(const std::string& statusMessage) { LOG_DEBUG("[UI Display] Status update: %s\n", statusMessage.c_str()); updateStatusLog(QString::fromStdString(statusMessage)); } void MainWindow::OnDetectionResult(const TunnelDetectionResult& result) { // 通过信号槽机制更新UI(确保在主线程中执行) emit detectionResultUpdateRequested(result); } void MainWindow::OnCamera1StatusChanged(bool isConnected) { // 直接更新设备状态widget if (m_deviceStatusWidget) { m_deviceStatusWidget->updateCamera1Status(isConnected); } } void MainWindow::OnCamera2StatusChanged(bool isConnected) { // 直接更新设备状态widget if (m_deviceStatusWidget) { m_deviceStatusWidget->updateCamera2Status(isConnected); } } void MainWindow::OnCameraCountChanged(int cameraCount) { // 设置设备状态widget中的相机数量 if (m_deviceStatusWidget) { m_deviceStatusWidget->setCameraCount(cameraCount); // 设置相机名称 if (m_presenter) { const auto& cameraList = m_presenter->GetCameraList(); if (cameraList.size() >= 1) { QString camera1Name = QString::fromStdString(cameraList[0].first); m_deviceStatusWidget->setCamera1Name(camera1Name); } if (cameraList.size() >= 2) { QString camera2Name = QString::fromStdString(cameraList[1].first); m_deviceStatusWidget->setCamera2Name(camera2Name); } } } // 更新状态消息 updateStatusLog(tr("3D相机数量: %1").arg(cameraCount)); } void MainWindow::OnRobotConnectionChanged(bool isConnected) { // 直接更新设备状态widget if (m_deviceStatusWidget) { m_deviceStatusWidget->updateRobotStatus(isConnected); } } void MainWindow::OnSerialConnectionChanged(bool isConnected) { // 直接更新设备状态widget if (m_deviceStatusWidget) { m_deviceStatusWidget->updateSerialStatus(isConnected); } } void MainWindow::OnWorkStatusChanged(WorkStatus status) { // 通过信号槽机制更新UI(确保在主线程中执行) emit workStatusUpdateRequested(status); } void MainWindow::OnHikImageUpdated(const QImage& image) { // 通过信号槽机制更新UI(确保在主线程中执行) emit hikImageUpdateRequested(image); } void MainWindow::updateWorkStatusLabel(WorkStatus status) { // 如果状态变为Working,清空检测日志(表示开始新的检测) if (status == WorkStatus::Working) { clearDetectionLog(); } // 获取状态对应的显示文本 QString statusText = QString::fromStdString(WorkStatusToString(status)); // 在label_work中显示状态 if (!ui->label_work) return; ui->label_work->setText(statusText); statusText = "【工作状态】" + statusText; updateStatusLog(statusText); // 根据不同状态设置不同的样式和按钮启用状态 switch (status) { case WorkStatus::Ready: ui->label_work->setStyleSheet("color: green;"); setButtonsEnabled(true); break; case WorkStatus::InitIng: ui->label_work->setStyleSheet("color: blue;"); setButtonsEnabled(false); break; case WorkStatus::Working: ui->label_work->setStyleSheet("color: blue;"); setButtonsEnabled(false); break; case WorkStatus::Completed: ui->label_work->setStyleSheet("color: green; font-weight: bold;"); setButtonsEnabled(true); break; case WorkStatus::Error: ui->label_work->setStyleSheet("color: red; font-weight: bold;"); setButtonsEnabled(true); break; default: ui->label_work->setStyleSheet(""); setButtonsEnabled(false); break; } } void MainWindow::updateDetectionResultDisplay(const TunnelDetectionResult& result) { // 显示3D点云图像 if (!result.image.isNull()) { updateDetectionLog(tr("3D检测结果更新")); display3DImage(result.image); } // 显示2D图像(海康相机) if (!result.hikImage.isNull()) { updateDetectionLog(tr("2D图像更新")); display2DImage(result.hikImage); } // 更新检测结果到列表 addDetectionResult(result); } void MainWindow::updateHikImageDisplay(const QImage& image) { display2DImage(image); } void MainWindow::updateDetectionLog(const QString& message) { // 在UI线程中更新detect_log控件 if (!m_logModel) return; // 获取当前数据 QStringList logList = m_logModel->stringList(); // 检查是否与最后一条消息相同 if (message == m_lastLogMessage && !logList.isEmpty()) { // 相同消息,增加计数并替换最后一条 m_lastLogCount++; // 添加时间戳 QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss"); QString logEntry = QString("[%1] %2 (x%3)").arg(timestamp).arg(message).arg(m_lastLogCount); // 替换最后一条 logList[logList.size() - 1] = logEntry; } else { // 新消息,重置计数 m_lastLogMessage = message; m_lastLogCount = 1; // 添加时间戳 QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss"); QString logEntry = QString("[%1] %2").arg(timestamp).arg(message); // 添加新的日志条目 logList.append(logEntry); } // 更新模型 m_logModel->setStringList(logList); // 自动滚动到最底部 QModelIndex lastIndex = m_logModel->index(logList.size() - 1); ui->detect_log->scrollTo(lastIndex); } void MainWindow::clearDetectionLogUI() { // 在UI线程中清空检测日志 if (m_logModel) { m_logModel->setStringList(QStringList()); } // 重置日志计数器 m_lastLogMessage.clear(); m_lastLogCount = 0; } void MainWindow::on_btn_start_clicked() { // 检查Presenter是否已初始化 if (!m_presenter) { updateStatusLog(tr("系统未初始化,请等待初始化完成")); return; } // 清空检测日志,开始新的检测 clearDetectionLog(); // 使用Presenter启动检测 m_presenter->StartDetection(-1, false); } void MainWindow::on_btn_stop_clicked() { // 检查Presenter是否已初始化 if (!m_presenter) { updateStatusLog(tr("系统未初始化,请等待初始化完成")); return; } m_presenter->StopDetection(); } void MainWindow::on_btn_camera_clicked() { // 检查是否有其他按钮已被选中 if (m_selectedButton != nullptr && m_selectedButton != ui->btn_camera) { updateStatusLog(tr("请先关闭当前打开的配置窗口")); return; } // 检查Presenter是否已初始化 if (!m_presenter) { updateStatusLog(tr("系统未初始化,请等待初始化完成")); return; } // 设置当前按钮为选中状态 setButtonSelectedState(ui->btn_camera, true); // 如果对话框不存在,创建新的CommonDialogCamera if (nullptr == ui_dialogCamera) { ui_dialogCamera = new CommonDialogCamera(m_presenter->GetCameraList(), this); // 连接对话框关闭信号 connect(ui_dialogCamera, &QDialog::finished, this, [this]() { setButtonSelectedState(ui->btn_camera, false); }); } ui_dialogCamera->show(); } void MainWindow::on_btn_algo_config_clicked() { // 检查是否有其他按钮已被选中 if (m_selectedButton != nullptr && m_selectedButton != ui->btn_algo_config) { updateStatusLog(tr("请先关闭当前打开的配置窗口")); return; } // 检查Presenter是否已初始化 if (!m_presenter) { updateStatusLog(tr("系统未初始化,请等待初始化完成")); return; } // 设置当前按钮为选中状态 setButtonSelectedState(ui->btn_algo_config, true); // TODO: 创建算法配置对话框 updateStatusLog(tr("算法配置功能待实现")); // 恢复按钮状态 setButtonSelectedState(ui->btn_algo_config, false); } void MainWindow::on_btn_camera_levelling_clicked() { // 检查是否有其他按钮已被选中 if (m_selectedButton != nullptr && m_selectedButton != ui->btn_camera_levelling) { updateStatusLog(tr("请先关闭当前打开的配置窗口")); return; } // 检查Presenter是否已初始化 if (!m_presenter) { updateStatusLog(tr("系统未初始化,请等待初始化完成")); return; } // 设置当前按钮为选中状态 setButtonSelectedState(ui->btn_camera_levelling, true); if(nullptr == ui_dialogCameraLevel){ ui_dialogCameraLevel = new CommonDialogCameraLevel(this); // 连接对话框关闭信号 connect(ui_dialogCameraLevel, &QDialog::finished, this, [this]() { setButtonSelectedState(ui->btn_camera_levelling, false); }); } // 设置相机列表、presenter、计算器和结果保存器到对话框 ui_dialogCameraLevel->SetCameraList(m_presenter->GetCameraList(), m_presenter, m_presenter, m_presenter); ui_dialogCameraLevel->show(); } void MainWindow::on_btn_hide_clicked() { // 最小化窗口 this->showMinimized(); } void MainWindow::on_btn_close_clicked() { // 关闭应用程序 this->close(); } void MainWindow::on_btn_test_clicked() { // 检查是否有其他按钮已被选中 if (m_selectedButton != nullptr && m_selectedButton != ui->btn_test) { updateStatusLog(tr("请先关闭当前打开的配置窗口")); return; } // 设置当前按钮为选中状态 setButtonSelectedState(ui->btn_test, true); // 打开文件选择对话框 QString fileName = QFileDialog::getOpenFileName( this, tr("选择调试数据文件"), QString(), tr("激光数据文件 (*.txt);;所有文件 (*.*)") ); if (fileName.isEmpty()) { // 用户取消了文件选择,恢复按钮状态 setButtonSelectedState(ui->btn_test, false); return; } // 检查Presenter是否已初始化 if (!m_presenter) { // 恢复按钮状态 setButtonSelectedState(ui->btn_test, false); QMessageBox::warning(this, tr("错误"), tr("系统未正确初始化!")); return; } // 清空检测日志,开始新的检测 clearDetectionLog(); std::thread t([this, fileName]() { int result = m_presenter->LoadDebugDataAndDetect(fileName.toStdString()); if (result == 0) { updateStatusLog(tr("调试数据加载和检测成功")); } else { QString errorMsg = tr("调试数据复检失败: %1").arg(result); updateStatusLog(errorMsg); } // 测试完成后恢复按钮状态 QMetaObject::invokeMethod(this, [this]() { setButtonSelectedState(ui->btn_test, false); }, Qt::QueuedConnection); }); t.detach(); } // 设置按钮启用/禁用状态 void MainWindow::setButtonsEnabled(bool enabled) { // 功能按钮 if (ui->btn_start) ui->btn_start->setEnabled(enabled); if (ui->btn_stop) ui->btn_stop->setEnabled(enabled); if (ui->btn_camera) ui->btn_camera->setEnabled(enabled); if (ui->btn_algo_config) ui->btn_algo_config->setEnabled(enabled); if (ui->btn_camera_levelling) ui->btn_camera_levelling->setEnabled(enabled); } // 设置按钮图像 void MainWindow::setButtonImage(QPushButton* button, const QString& imagePath) { if (button) { QString styleSheet = QString("image: url(%1);background-color: rgb(38, 40, 47);border: none;").arg(imagePath); button->setStyleSheet(styleSheet); } } // 设置按钮选中状态 void MainWindow::setButtonSelectedState(QPushButton* button, bool selected) { if (!button) return; QString normalImage, selectedImage; // 根据按钮确定对应的图像路径 if (button == ui->btn_camera) { normalImage = ":/common/resource/config_camera.png"; selectedImage = ":/common/resource/config_camera_s.png"; } else if (button == ui->btn_algo_config) { normalImage = ":/common/resource/config_algo.png"; selectedImage = ":/common/resource/config_algo_s.png"; } else if (button == ui->btn_camera_levelling) { normalImage = ":/common/resource/config_camera_level.png"; selectedImage = ":/common/resource/config_camera_level_s.png"; } else if (button == ui->btn_test) { normalImage = ":/common/resource/config_data_test.png"; selectedImage = ":/common/resource/config_data_test_s.png"; } // 设置对应的图像 if (selected) { setButtonImage(button, selectedImage); m_selectedButton = button; // 禁用其他按钮 setOtherButtonsEnabled(button, false); } else { setButtonImage(button, normalImage); if (m_selectedButton == button) { m_selectedButton = nullptr; // 启用所有按钮 setOtherButtonsEnabled(nullptr, true); } } } // 恢复所有按钮状态 void MainWindow::restoreAllButtonStates() { setButtonSelectedState(ui->btn_camera, false); setButtonSelectedState(ui->btn_algo_config, false); setButtonSelectedState(ui->btn_camera_levelling, false); setButtonSelectedState(ui->btn_test, false); } // 设置其他按钮的启用状态(用于互斥控制) void MainWindow::setOtherButtonsEnabled(QPushButton* exceptButton, bool enabled) { QList configButtons = { ui->btn_camera, ui->btn_algo_config, ui->btn_camera_levelling, ui->btn_test }; for (QPushButton* button : configButtons) { if (button && button != exceptButton) { button->setEnabled(enabled); } } } // 处理相机点击事件 void MainWindow::onCameraClicked(int cameraIndex) { if (m_presenter) { m_presenter->SetDefaultCameraIndex(cameraIndex); } } // 设置右键菜单 void MainWindow::setupContextMenu() { // 创建右键菜单 m_contextMenu = new QMenu(this); // 创建保存数据动作 m_saveDataAction = new QAction(tr("保存检测数据"), this); // 设置右键菜单的样式表 m_contextMenu->setStyleSheet( "QMenu::item { color: gray; }" "QMenu::item:enabled { color: gray; }" "QMenu::item:disabled { color: gray; }" ); // 添加动作到菜单 m_contextMenu->addAction(m_saveDataAction); // 连接信号槽 connect(m_saveDataAction, &QAction::triggered, this, &MainWindow::onSaveDetectionData); // 为图像视图设置右键菜单事件 ui->detect_image_3d->setContextMenuPolicy(Qt::CustomContextMenu); ui->detect_image_2d->setContextMenuPolicy(Qt::CustomContextMenu); // 连接右键菜单信号 connect(ui->detect_image_3d, &QGraphicsView::customContextMenuRequested, this, [this](const QPoint& pos) { showContextMenu(pos, ui->detect_image_3d); }); connect(ui->detect_image_2d, &QGraphicsView::customContextMenuRequested, this, [this](const QPoint& pos) { showContextMenu(pos, ui->detect_image_2d); }); } // 显示右键菜单 void MainWindow::showContextMenu(const QPoint& pos, QGraphicsView* view) { // 检查是否有检测数据可以保存 if (!m_presenter) { updateStatusLog(tr("系统未初始化,无法保存数据")); return; } if (m_presenter->GetDetectionDataCacheSize() == 0) { updateStatusLog(tr("没有检测数据可以保存")); return; } // 显示右键菜单 m_contextMenu->exec(view->mapToGlobal(pos)); } // 保存检测数据槽函数 void MainWindow::onSaveDetectionData() { if (!m_presenter) { updateStatusLog(tr("系统未初始化,无法保存数据")); return; } // 让用户选择保存目录 QString dirPath = QFileDialog::getExistingDirectory(this, tr("选择保存目录"), QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); if (dirPath.isEmpty()) { updateStatusLog(tr("用户取消了保存操作")); return; } // 生成文件名(包含时间戳和相机信息) std::string timeStamp = CVrDateUtils::GetNowTime(); std::string fileName = "Laserline_" + std::to_string(m_presenter->GetDetectIndex()) + "_" + timeStamp + ".txt"; QString fullPath = QDir(dirPath).filePath(QString::fromStdString(fileName)); // 保存数据 if (saveDetectionDataToFile(fullPath, m_presenter->GetDetectIndex())) { updateStatusLog(tr("检测数据已保存到:%1").arg(fileName.c_str())); } else { updateStatusLog(tr("保存检测数据失败")); } } // 保存检测数据到文件 bool MainWindow::saveDetectionDataToFile(const QString& filePath, int cameraIndex) { try { // 直接调用Presenter的保存方法 int result = m_presenter->SaveDetectionDataToFile(filePath.toStdString()); if (result == 0) { updateStatusLog(tr("检测数据保存成功")); return true; } else { updateStatusLog(tr("保存数据失败,错误码:%1").arg(result)); return false; } } catch (const std::exception& e) { updateStatusLog(tr("保存数据时发生异常:%1").arg(e.what())); return false; } } // ============ 补光灯控制相关 ============ void MainWindow::setupSupplementLightButton() { return; // 创建补光灯按钮(悬浮在2D图像视图上) m_btnSupplementLight = new QPushButton(ui->detect_image_2d); m_btnSupplementLight->setFixedSize(32, 32); m_btnSupplementLight->setToolTip(tr("补光灯开关")); m_btnSupplementLight->setCursor(Qt::PointingHandCursor); m_btnSupplementLight->setFlat(true); m_btnSupplementLight->setAttribute(Qt::WA_TranslucentBackground); m_btnSupplementLight->setAutoFillBackground(false); // 设置按钮样式 updateSupplementLightButtonState(false); // 设置初始位置到右上角 int viewWidth = ui->detect_image_2d->width(); if (viewWidth < 100) viewWidth = 400; m_btnSupplementLight->move(viewWidth - 42, 10); m_btnSupplementLight->raise(); m_btnSupplementLight->show(); connect(m_btnSupplementLight, &QPushButton::clicked, this, &MainWindow::onSupplementLightToggle); ui->detect_image_2d->installEventFilter(this); } void MainWindow::updateSupplementLightButtonState(bool enabled) { if (!m_btnSupplementLight) return; m_bSupplementLightOn = enabled; // 简单的圆形指示灯样式 if (enabled) { m_btnSupplementLight->setStyleSheet( "QPushButton { background: qradialgradient(cx:0.5, cy:0.5, radius:0.5, fx:0.3, fy:0.3, stop:0 #FFFF00, stop:1 #FF8C00); " "border: 2px solid #FFD700; border-radius: 16px; }" "QPushButton:hover { border: 2px solid #FFFFFF; }" ); } else { m_btnSupplementLight->setStyleSheet( "QPushButton { background: qradialgradient(cx:0.5, cy:0.5, radius:0.5, fx:0.3, fy:0.3, stop:0 #666666, stop:1 #333333); " "border: 2px solid #555555; border-radius: 16px; }" "QPushButton:hover { border: 2px solid #888888; }" ); } m_btnSupplementLight->setText(""); } void MainWindow::onSupplementLightToggle() { if (!m_presenter) { updateStatusLog(tr("系统未初始化")); return; } // 切换状态 bool newState = !m_bSupplementLightOn; // TODO: 在此处添加控制其他补光设备的代码 // 例如:通过串口、Modbus、GPIO等方式控制外部补光灯 // int result = m_presenter->SetExternalSupplementLight(newState); // 暂时直接更新UI状态 updateSupplementLightButtonState(newState); updateStatusLog(tr("补光灯已%1").arg(newState ? tr("开启") : tr("关闭"))); } bool MainWindow::eventFilter(QObject* watched, QEvent* event) { // 处理2D图像视图的resize和show事件,重新定位补光灯按钮到右上角 if (watched == ui->detect_image_2d) { if (event->type() == QEvent::Resize || event->type() == QEvent::Show) { if (m_btnSupplementLight) { int viewWidth = ui->detect_image_2d->width(); m_btnSupplementLight->move(viewWidth - 42, 10); m_btnSupplementLight->raise(); } } } return QMainWindow::eventFilter(watched, event); }