#include "mainwindow.h" #include "ui_mainwindow.h" #include "XyzRpyItem.h" #include "ResultListLayoutHelper.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 "RodAndBarPositionPresenter.h" #include #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); #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); statusBar()->setStyleSheet("QStatusBar { color: rgb(239, 241, 245); padding: 20px; }"); QString versionWithBuildTime = QString("%1_%2%3%4%5%6%7") .arg(GetRodAndBarPositionFullVersion()) .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;"); buildLabel->setCursor(Qt::PointingHandCursor); buildLabel->installEventFilter(this); statusBar()->addPermanentWidget(buildLabel); m_versionLabel = buildLabel; setWindowFlags(Qt::FramelessWindowHint); this->showMaximized(); ui->label_work->setVisible(false); ui->detect_image_2->setVisible(false); QGraphicsScene* scene = new QGraphicsScene(this); ui->detect_image->setScene(scene); // 为第二个图像视图初始化GraphicsScene QGraphicsScene* scene2 = new QGraphicsScene(this); ui->detect_image_2->setScene(scene2); m_logHelper = new DetectLogHelper(ui->detect_log, this); qRegisterMetaType("DetectionResult"); qRegisterMetaType("WorkStatus"); qRegisterMetaType("RodPosition"); connect(this, &MainWindow::workStatusUpdateRequested, this, &MainWindow::updateWorkStatusLabel); connect(this, &MainWindow::detectionResultUpdateRequested, this, &MainWindow::updateDetectionResultDisplay); setupContextMenu(); updateStatusLog(tr("设备开始初始化...")); Init(); } MainWindow::~MainWindow() { if (m_presenter) { m_presenter->SetStatusCallback(static_cast(nullptr)); m_presenter->DeinitApp(); delete m_presenter; m_presenter = nullptr; } delete ui; } void MainWindow::updateStatusLog(const QString& message) { if (m_logHelper) { m_logHelper->appendLog(message); } } void MainWindow::clearDetectionLog() { if (m_logHelper) { m_logHelper->clearLog(); } } void MainWindow::Init() { m_presenter = new RodAndBarPositionPresenter(); m_presenter->SetStatusCallback(this); m_deviceStatusWidget = new DeviceStatusWidget(); connect(m_deviceStatusWidget, SIGNAL(cameraClicked(int)), this, SLOT(onCameraClicked(int))); 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); setButtonsEnabled(false); std::thread initThread([this]() { updateStatusLog(tr("正在初始化系统...")); int result = m_presenter->Init(); if (result != 0) { updateStatusLog(tr("初始化失败,错误码:%1").arg(result)); } else { updateStatusLog(tr("系统初始化完成")); } }); initThread.detach(); } void MainWindow::displayImage(const QImage& image) { if (image.isNull()) { updateStatusLog(tr("图片无效")); return; } QGraphicsScene* scene = ui->detect_image->scene(); scene->clear(); QPixmap pixmap = QPixmap::fromImage(image); scene->addPixmap(pixmap); ui->detect_image->fitInView(scene->sceneRect(), Qt::KeepAspectRatio); } // 在第二个图像视图中显示图像 void MainWindow::displayImageInSecondView(const QImage& image) { if (image.isNull()) { updateStatusLog(tr("第二相机图片无效")); return; } QGraphicsScene* scene2 = ui->detect_image_2->scene(); scene2->clear(); QPixmap pixmap = QPixmap::fromImage(image); scene2->addPixmap(pixmap); ui->detect_image_2->fitInView(scene2->sceneRect(), Qt::KeepAspectRatio); } void MainWindow::addDetectionResult(const DetectionResult& result) { ui->detect_result_list->clear(); int itemSpacing = 0; ui->detect_result_list->setSpacing(itemSpacing); // 获取当前的gridSize(由布局调整函数设置) QSize currentGridSize = ui->detect_result_list->gridSize(); int gridWidth = currentGridSize.width(); int gridHeight = currentGridSize.height(); for (size_t i = 0; i < result.positions.size(); i++) { XyzRpyItem* resultWidget = new XyzRpyItem(); resultWidget->setAutoFillBackground(true); resultWidget->setResultData(static_cast(i) + 1, "棒材", result.positions[i]); QListWidgetItem* item = new QListWidgetItem(); item->setBackground(QBrush(Qt::transparent)); item->setSizeHint(QSize(gridWidth, gridHeight)); 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 DetectionResult& result) { emit detectionResultUpdateRequested(result); } void MainWindow::OnCamera1StatusChanged(bool isConnected) { if (m_deviceStatusWidget) { m_deviceStatusWidget->updateCamera1Status(isConnected); } } void MainWindow::OnCamera2StatusChanged(bool isConnected) { if (m_deviceStatusWidget) { m_deviceStatusWidget->updateCamera2Status(isConnected); } } void MainWindow::OnCameraCountChanged(int cameraCount) { if (m_deviceStatusWidget) { m_deviceStatusWidget->setCameraCount(cameraCount); if (m_presenter) { const auto& cameraList = m_presenter->GetCameraList(); if (cameraList.size() >= 1) { m_deviceStatusWidget->setCamera1Name(QString::fromStdString(cameraList[0].first)); } if (cameraList.size() >= 2) { m_deviceStatusWidget->setCamera2Name(QString::fromStdString(cameraList[1].first)); } } } // 根据相机个数调整页面布局 adjustLayoutForCameraCount(cameraCount); if (cameraCount < 2) { updateStatusLog(tr("系统使用单相机模式")); } else { updateStatusLog(tr("系统使用双相机模式")); } } void MainWindow::OnRobotConnectionChanged(bool isConnected) { if (m_deviceStatusWidget) { m_deviceStatusWidget->updateRobotStatus(isConnected); } } void MainWindow::OnSerialConnectionChanged(bool isConnected) { if (m_deviceStatusWidget) { m_deviceStatusWidget->updateSerialStatus(isConnected); } } void MainWindow::OnWorkStatusChanged(WorkStatus status) { emit workStatusUpdateRequested(status); } void MainWindow::updateWorkStatusLabel(WorkStatus status) { if (status == WorkStatus::Working) { clearDetectionLog(); } QString statusText = QString::fromStdString(WorkStatusToString(status)); 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 DetectionResult& result) { // 根据相机索引决定显示在哪个图像视图上 if (result.cameraIndex == 2) { updateStatusLog(tr("相机2检测结果更新")); displayImageInSecondView(result.image); } else { updateStatusLog(tr("相机1检测结果更新")); displayImage(result.image); } addDetectionResult(result); } void MainWindow::on_btn_start_clicked() { if (!m_presenter) { updateStatusLog(tr("系统未初始化,请等待初始化完成")); return; } clearDetectionLog(); m_presenter->StartDetection(-1, false); } void MainWindow::on_btn_stop_clicked() { 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; } if (!m_presenter) { updateStatusLog(tr("系统未初始化,请等待初始化完成")); return; } setButtonSelectedState(ui->btn_camera, true); 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; } if (!m_presenter) { updateStatusLog(tr("系统未初始化,请等待初始化完成")); return; } setButtonSelectedState(ui->btn_algo_config, true); if(nullptr == ui_dialogConfig){ ui_dialogConfig = new DialogAlgoArg(this); ui_dialogConfig->SetPresenter(m_presenter); connect(ui_dialogConfig, &QDialog::finished, this, [this]() { setButtonSelectedState(ui->btn_algo_config, false); }); } ui_dialogConfig->show(); } void MainWindow::on_btn_camera_levelling_clicked() { if (m_selectedButton != nullptr && m_selectedButton != ui->btn_camera_levelling) { updateStatusLog(tr("请先关闭当前打开的配置窗口")); return; } 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); }); } 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; } 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 { updateStatusLog(tr("调试数据复检失败: %1").arg(result)); } 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) { button->setStyleSheet(QString("image: url(%1);background-color: rgb(38, 40, 47);border: none;").arg(imagePath)); } } 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->setContextMenuPolicy(Qt::CustomContextMenu); ui->detect_image_2->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui->detect_image, &QGraphicsView::customContextMenuRequested, this, [this](const QPoint& pos) { showContextMenu(pos, ui->detect_image); }); connect(ui->detect_image_2, &QGraphicsView::customContextMenuRequested, this, [this](const QPoint& pos) { showContextMenu(pos, ui->detect_image_2); }); } void MainWindow::showContextMenu(const QPoint& pos, QGraphicsView* view) { if (!m_presenter) { updateStatusLog(tr("系统未初始化,无法保存数据")); return; } // 根据视图确定相机索引 int cameraIndex = (view == ui->detect_image_2) ? 2 : 1; if (cameraIndex != m_presenter->GetDetectIndex()) { 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 { 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::adjustLayoutForCameraCount(int cameraCount) { if (cameraCount <= 1) { setupSingleCameraLayout(); } else { setupMultiCameraLayout(); } } // 获取可用高度(屏幕高度 - 任务栏 - 边距) int MainWindow::getAvailableHeight() { QScreen* screen = QApplication::primaryScreen(); if (screen) { QRect availableGeometry = screen->availableGeometry(); return availableGeometry.height() - 30; } return 1050; } // 设置单相机模式布局 void MainWindow::setupSingleCameraLayout() { int availableHeight = getAvailableHeight(); ResultListLayoutHelper::setupSingleCameraMode( ui->detect_result_list, ui->detect_image, ui->detect_image_2, ui->frame_dev, ui->detect_log, availableHeight); m_deviceStatusWidget->setCameraCount(1); updateStatusLog(tr("页面布局已调整为单相机模式")); } // 设置多相机模式布局 void MainWindow::setupMultiCameraLayout() { int availableHeight = getAvailableHeight(); ResultListLayoutHelper::setupMultiCameraMode( ui->detect_result_list, ui->detect_image, ui->detect_image_2, ui->frame_dev, ui->detect_log, availableHeight); m_deviceStatusWidget->setCameraCount(2); updateStatusLog(tr("页面布局已调整为多相机模式")); } // 事件过滤器:点击版本标签弹出关于对话框 bool MainWindow::eventFilter(QObject* obj, QEvent* event) { if (obj == m_versionLabel && event->type() == QEvent::MouseButtonPress) { QString versionStr = m_versionLabel->text(); QString algoVersion = m_presenter ? m_presenter->GetAlgoVersion() : QString(); AboutDialog dlg(RODANDBARPOSITION_APP_NAME, versionStr, algoVersion, this); dlg.exec(); return true; } return QMainWindow::eventFilter(obj, event); }