#include "mainwindow.h" #include "ui_mainwindow.h" #include "Version.h" #include "widgets/ImageGridWidget.h" #include "widgets/DeviceStatusWidget.h" #include "widgets/MeasureResultListWidget.h" #include "dialogcameralevel.h" #include "dialogalgoarg.h" #include "dialogcamera.h" #include #include #include #include #include #include #include #include #include #include #include "VrLog.h" #include "IVrUtils.h" #include "StyledMessageBox.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); // 设置窗口图标 this->setWindowIcon(QIcon(":/common/resource/logo.png")); // 设置状态栏字体 QFont statusFont = statusBar()->font(); statusFont.setPointSize(12); statusBar()->setFont(statusFont); // 设置状态栏颜色和padding statusBar()->setStyleSheet("QStatusBar { color: rgb(239, 241, 245); padding: 20px; }"); // 隐藏标题栏 setWindowFlags(Qt::FramelessWindowHint); // 启动后自动最大化显示 this->showMaximized(); // 初始化时隐藏工作状态标签 ui->label_work->setVisible(false); // 创建组合控件 m_gridView = new ImageGridWidget(); m_deviceStatusWidget = new DeviceStatusWidget(); m_measureResultWidget = new MeasureResultListWidget(); // 将设备状态widget添加到frame_dev中 QVBoxLayout* frameResultImageLayout = new QVBoxLayout(ui->detect_result); frameResultImageLayout->setContentsMargins(0, 0, 0, 0); frameResultImageLayout->addWidget(m_gridView); // 将MeasureResultListWidget添加到detect_data中 QVBoxLayout* frameDataLayout = new QVBoxLayout(ui->detect_data); frameDataLayout->setContentsMargins(0, 0, 0, 0); frameDataLayout->addWidget(m_measureResultWidget); QVBoxLayout* frameDevLayout = new QVBoxLayout(ui->device_status); frameDevLayout->setContentsMargins(0, 0, 0, 0); frameDevLayout->addWidget(m_deviceStatusWidget); // 初始化Presenter m_presenter = new WheelMeasurePresenter(); // 将设备状态控件与Presenter关联 m_presenter->setStatusUpdate(this); // 连接配置更新信号 connect(m_presenter, &WheelMeasurePresenter::configUpdated, this, &MainWindow::onConfigSaved); // 连接设备点击信号到重新检测槽函数 connect(m_deviceStatusWidget, &DeviceStatusWidget::deviceClicked, this, &MainWindow::onDeviceClicked); // 连接图像右键点击信号到保存数据槽函数 connect(m_gridView, &ImageGridWidget::tileRightClicked, this, &MainWindow::onTileRightClicked); // 设置版本信息显示 setupVersionDisplay(); // 初始化日志辅助类 m_logHelper = new DetectLogHelper(ui->detect_log, this); m_presenter->Init(); } MainWindow::~MainWindow() { // 先清除回调,防止后台线程继续调用 if (m_presenter) { m_presenter->setStatusUpdate(nullptr); } if (m_gridView) { delete m_gridView; m_gridView = nullptr; } if (m_deviceStatusWidget) { delete m_deviceStatusWidget; m_deviceStatusWidget = nullptr; } if (m_measureResultWidget) { delete m_measureResultWidget; m_measureResultWidget = nullptr; } if (m_versionLabel) { delete m_versionLabel; m_versionLabel = nullptr; } if (m_dialogAlgoArg) { delete m_dialogAlgoArg; m_dialogAlgoArg = nullptr; } if (m_dialogCamera) { delete m_dialogCamera; m_dialogCamera = nullptr; } if (m_dialogCameraLevel) { delete m_dialogCameraLevel; m_dialogCameraLevel = nullptr; } if (m_presenter) { delete m_presenter; m_presenter = nullptr; } delete ui; LOG_DEBUG("~MainWindow finish \n"); } void MainWindow::resizeEvent(QResizeEvent* event) { QMainWindow::resizeEvent(event); } void MainWindow::on_btn_hide_clicked() { this->showMinimized(); } void MainWindow::on_btn_close_clicked() { this->close(); } void MainWindow::on_btn_test_clicked() { if (!m_presenter) { QMessageBox::warning(this, "错误", "系统未初始化完成!"); return; } // 设置选中状态 ui->btn_test->setStyleSheet( "QPushButton { image: url(:/common/resource/config_data_test_s.png); background-color: rgb(38, 40, 47); border: none; }" ); // 打开文件选择对话框 QString fileName = QFileDialog::getOpenFileName( this, tr("选择调试数据文件"), QString(), tr("激光数据文件 (*.txt);;所有文件 (*.*)") ); // 恢复未选中状态 ui->btn_test->setStyleSheet( "QPushButton { image: url(:/common/resource/config_data_test.png); background-color: rgb(38, 40, 47); border: none; }" "QPushButton:pressed { image: url(:/common/resource/config_data_test_s.png); }" ); if (fileName.isEmpty()) { return; } // 清空当前检测数据列表 if (m_measureResultWidget) { m_measureResultWidget->clearAllResults(); } // if (m_logHelper) m_logHelper->appendLog(QString("正在加载调试数据: %1").arg(fileName)); // 在后台线程中执行加载和检测 std::thread t([this, fileName]() { int result = m_presenter->LoadDebugDataAndDetect(fileName.toStdString()); if (result == 0) { QMetaObject::invokeMethod(this, [this]() { if (m_logHelper) m_logHelper->appendLog("调试数据加载和检测成功"); }, Qt::QueuedConnection); } else { QMetaObject::invokeMethod(this, [this, result]() { if (m_logHelper) m_logHelper->appendLog(QString("调试数据复检失败: %1").arg(result)); }, Qt::QueuedConnection); } }); t.detach(); } void MainWindow::on_btn_start_clicked() { if (!m_presenter) { QMessageBox::warning(this, "错误", "系统未初始化完成!"); return; } // 启动所有相机的检测 m_presenter->StartAllDetection(); if (m_logHelper) m_logHelper->appendLog("已启动所有相机检测"); } void MainWindow::on_btn_stop_clicked() { if (!m_presenter) { return; } // 停止所有相机的检测 m_presenter->StopAllDetection(); if (m_logHelper) m_logHelper->appendLog("已停止所有相机检测"); } void MainWindow::on_btn_camera_config_clicked() { if (!m_presenter) { QMessageBox::warning(this, "错误", "系统未初始化完成!"); return; } if (!m_dialogCamera) { m_dialogCamera = new DialogCamera(this); m_dialogCamera->SetPresenter(m_presenter); connect(m_dialogCamera, &DialogCamera::configSaved, this, &MainWindow::onConfigSaved); // 连接关闭信号恢复按钮状态 connect(m_dialogCamera, &QDialog::finished, this, [this]() { ui->btn_camera_config->setStyleSheet( "QPushButton { image: url(:/common/resource/config_camera.png); background-color: rgb(38, 40, 47); border: none; }" "QPushButton:pressed { image: url(:/common/resource/config_camera_s.png); }" ); }); } // 设置选中状态 ui->btn_camera_config->setStyleSheet( "QPushButton { image: url(:/common/resource/config_camera_s.png); background-color: rgb(38, 40, 47); border: none; }" ); m_dialogCamera->show(); } void MainWindow::on_btn_algo_config_clicked() { if (!m_presenter) { QMessageBox::warning(this, "错误", "系统未初始化完成!"); return; } if (!m_dialogAlgoArg) { m_dialogAlgoArg = new DialogAlgoArg(m_presenter->GetConfig(), m_presenter->GetConfigResult(), this); // 连接关闭信号恢复按钮状态 connect(m_dialogAlgoArg, &QDialog::finished, this, [this]() { ui->btn_algo_config->setStyleSheet( "QPushButton { image: url(:/common/resource/config_algo.png); background-color: rgb(38, 40, 47); border: none; }" "QPushButton:pressed { image: url(:/common/resource/config_algo_s.png); }" ); }); } // 设置选中状态 ui->btn_algo_config->setStyleSheet( "QPushButton { image: url(:/common/resource/config_algo_s.png); background-color: rgb(38, 40, 47); border: none; }" ); m_dialogAlgoArg->Init(); m_dialogAlgoArg->show(); } void MainWindow::on_btn_camera_level_clicked() { if (!m_presenter) { QMessageBox::warning(this, "错误", "系统未初始化完成!"); return; } if (!m_dialogCameraLevel) { m_dialogCameraLevel = new DialogCameraLevel(this); // 连接关闭信号恢复按钮状态 connect(m_dialogCameraLevel, &QDialog::finished, this, [this]() { ui->btn_camera_level->setStyleSheet( "QPushButton { image: url(:/common/resource/config_camera_level.png); background-color: rgb(38, 40, 47); border: none; }" "QPushButton:pressed { image: url(:/common/resource/config_camera_level_s.png); }" ); }); } // 设置相机列表 m_dialogCameraLevel->setCameraList(m_presenter->GetCameraList(), m_presenter); // 设置配置对象 m_dialogCameraLevel->setConfig(m_presenter->GetConfig(), m_presenter->GetConfigResult()); // 设置选中状态 ui->btn_camera_level->setStyleSheet( "QPushButton { image: url(:/common/resource/config_camera_level_s.png); background-color: rgb(38, 40, 47); border: none; }" ); m_dialogCameraLevel->show(); } void MainWindow::onDeviceClicked(const QString& deviceName) { if (!m_presenter) { QMessageBox::warning(this, "错误", "系统未初始化完成!"); return; } // 查找相机索引 auto cameraList = m_presenter->GetCameraList(); int foundIndex = -1; for (int i = 0; i < static_cast(cameraList.size()); ++i) { if (QString::fromStdString(cameraList[i].first) == deviceName) { foundIndex = i; break; } } if (foundIndex < 0) { if (m_logHelper) m_logHelper->appendLog(QString("未找到相机: %1").arg(deviceName)); return; } // 清空指定设备的检测结果 if (m_measureResultWidget) { m_measureResultWidget->clearDeviceResult(deviceName); } // 直接开始检测 m_presenter->ResetDetect(foundIndex); if (m_logHelper) m_logHelper->appendLog(QString("已启动相机 \"%1\" 的检测").arg(deviceName)); } void MainWindow::onConfigSaved() { // 配置已在 WheelMeasurePresenter::OnConfigChanged 中更新 // 算法参数和调平参数的修改不需要重新初始化相机 LOG_INFO("Config saved, configuration updated in memory\n"); } void MainWindow::onTileRightClicked(int index, const QString& alias) { if (!m_presenter) { StyledMessageBox::warning(this, "错误", "系统未初始化完成!"); return; } // 获取当前检测的相机索引(0-based) int currentDetectIndex = m_presenter->GetDetectIndex() - 1; // 转换为0-based // 检查点击的是否是当前检测的相机 if (index != currentDetectIndex) { if (m_logHelper) m_logHelper->appendLog(QString("设备 \"%1\" 无缓存数据").arg(alias)); StyledMessageBox::information(this, "提示", QString("设备 \"%1\" 无缓存数据\n\n当前缓存的是设备 %2 的数据") .arg(alias) .arg(currentDetectIndex >= 0 ? m_gridView->getAlias(currentDetectIndex) : "无")); return; } // 检查是否有缓存数据 int cacheSize = m_presenter->GetDetectionDataCacheSize(); if (cacheSize <= 0) { if (m_logHelper) m_logHelper->appendLog(QString("设备 \"%1\" 无缓存数据").arg(alias)); StyledMessageBox::information(this, "提示", QString("设备 \"%1\" 无缓存数据").arg(alias)); return; } // 弹出文件保存对话框 QString defaultFileName = QString("%1_%2.txt") .arg(alias) .arg(QDateTime::currentDateTime().toString("yyyyMMdd_HHmmss")); QString filePath = QFileDialog::getSaveFileName( this, tr("保存检测数据"), defaultFileName, tr("文本文件 (*.txt);;所有文件 (*.*)") ); if (filePath.isEmpty()) { return; } // 调用Presenter保存数据 int result = m_presenter->SaveDetectionDataToFile(filePath.toStdString()); if (result == 0) { if (m_logHelper) m_logHelper->appendLog(QString("检测数据已保存: %1").arg(filePath)); StyledMessageBox::information(this, "成功", QString("检测数据已保存到:\n%1").arg(filePath)); } else { if (m_logHelper) m_logHelper->appendLog(QString("保存检测数据失败: %1").arg(result)); StyledMessageBox::warning(this, "失败", QString("保存检测数据失败,错误码: %1").arg(result)); } } // IWheelMeasureStatus接口方法实现 void MainWindow::OnStatusUpdate(const QString &statusMessage) { if (m_logHelper) m_logHelper->appendLog(statusMessage); LOG_DEBUG("Status update: %s \n", statusMessage.toStdString().c_str()); } void MainWindow::OnNeedShowImageCount(const QStringList &cameraNames) { if (cameraNames.isEmpty()) { m_gridView->initImages(0); LOG_DEBUG("No images to display\n"); } else { m_gridView->initImages(cameraNames.size()); // 为每个tile设置别名 for (int i = 0; i < cameraNames.size(); ++i) { m_gridView->setTileAlias(i, cameraNames.at(i)); } // 初始化设备状态列表 if (m_deviceStatusWidget && m_presenter) { QList devices; for (const QString& name : cameraNames) { devices.append(WheelDeviceDisplayInfo(name, name, "", DeviceStatus::Offline, true)); } m_deviceStatusWidget->setDevices(devices); } // 初始化检测结果列表 if (m_measureResultWidget) { m_measureResultWidget->setDeviceList(cameraNames); } } } void MainWindow::OnMeasureResult(const WheelMeasureResult &result) { // 直接调用处理方法(Presenter在后台线程,需要使用invokeMethod确保线程安全) QMetaObject::invokeMethod(this, [this, result]() { // 如果图像有效,显示在网格控件中 if (result.bImageValid && !result.image.isNull()) { m_gridView->setImages(result.aliasName, result.image); } // 更新设备检测结果列表 if (m_measureResultWidget) { // 获取第一个结果数据(如果有的话) WheelMeasureData data; if (!result.result.empty()) { data = result.result[0]; } m_measureResultWidget->updateDeviceResult(result.cameraName, data, result.bResultValid); } }, Qt::QueuedConnection); } void MainWindow::OnCameraConnected(const QString &cameraName) { QString message = QString("相机已连接: %1").arg(cameraName); if (m_logHelper) m_logHelper->appendLog(message); LOG_DEBUG("%s \n", message.toStdString().c_str()); } void MainWindow::OnCameraDisconnected(const QString &cameraName) { QString message = QString("相机断开连接: %1").arg(cameraName); if (m_logHelper) m_logHelper->appendLog(message); LOG_DEBUG("%s \n", message.toStdString().c_str()); } void MainWindow::OnWorkStatusChangedImpl(WorkStatus status) { QString statusStr; switch (status) { case WorkStatus::InitIng: statusStr = "初始化中"; break; case WorkStatus::Ready: statusStr = "准备就绪"; break; case WorkStatus::Working: statusStr = "正在检测"; break; case WorkStatus::Detecting: statusStr = "正在检测"; break; case WorkStatus::Completed: statusStr = "检测完成"; break; case WorkStatus::Error: statusStr = "设备异常"; break; default: statusStr = "未知状态"; break; } QString message = QString("工作状态: %1").arg(statusStr); if (m_logHelper) m_logHelper->appendLog(message); LOG_DEBUG("%s \n", message.toStdString().c_str()); } void MainWindow::OnErrorOccurred(const QString &errorMessage) { if (m_logHelper) m_logHelper->appendLog("错误: " + errorMessage); LOG_ERROR("Error occurred: %s \n", errorMessage.toStdString().c_str()); } void MainWindow::OnDeviceStatusChanged(const QString &deviceName, int deviceStatus) { if (m_deviceStatusWidget) { m_deviceStatusWidget->updateDeviceStatus(deviceName, static_cast(deviceStatus)); } } void MainWindow::OnClearMeasureData() { if (m_measureResultWidget) { m_measureResultWidget->clearAllResults(); } } void MainWindow::setupVersionDisplay() { m_versionLabel = new QLabel(this); // 使用与 Workpiece 一致的版本格式 QString versionText = QString("%1_%2%3%4%5%6%7") .arg(GetWheelMeasureFullVersion()) .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')); m_versionLabel->setText(versionText); m_versionLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_versionLabel->setStyleSheet("QLabel { color: rgb(239, 241, 245); font-size: 24px; margin-right: 10px; }"); statusBar()->addPermanentWidget(m_versionLabel); LOG_INFO("Version display initialized: %s\n", versionText.toStdString().c_str()); }