GrabBag/App/LapWeld/LapWeldApp/mainwindow.cpp
2025-09-18 23:49:32 +08:00

965 lines
30 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 "resultitem.h"
#include <QGraphicsScene>
#include <QStandardItemModel>
#include <QDebug>
#include <QPainter>
#include <QBrush>
#include <QMessageBox>
#include <QFileDialog>
#include <QListWidgetItem>
#include <QtMath>
#include <QThread>
#include <QDateTime>
#include <QTextCursor>
#include <QStringListModel>
#include "VrLog.h"
#include <QIcon>
#include <QMetaType>
#include <QLabel>
#include <QVBoxLayout>
#include "Version.h"
#include "VrSimpleLog.h"
#include <QMenu>
#include <QAction>
#include <QStandardPaths>
#include <QDir>
#include <QGraphicsView>
#include "LapWeldPresenter.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
, m_selectedButton(nullptr)
, m_contextMenu(nullptr)
, m_saveDataAction(nullptr)
{
ui->setupUi(this);
// 设置窗口图标
this->setWindowIcon(QIcon(":/resource/logo.png"));
// 设置状态栏字体
QFont statusFont = statusBar()->font();
statusFont.setPointSize(12);
statusBar()->setFont(statusFont);
// 设置状态栏颜色和padding
statusBar()->setStyleSheet("QStatusBar { color: rgb(239, 241, 245); padding: 20px; }");
// 在状态栏右侧添加版本信息(包含编译时间)
// 使用VrSimpleLog.h中的宏定义构建编译时间
QString versionWithBuildTime = QString("%1_%2%3%4%5%6%7")
.arg(GetLapWeldFullVersion())
.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);
ui->detect_image_2->setVisible(false);
// 初始化GraphicsScene
QGraphicsScene* scene = new QGraphicsScene(this);
ui->detect_image->setScene(scene);
// 为第二个图像视图初始化GraphicsScene
QGraphicsScene* scene2 = new QGraphicsScene(this);
ui->detect_image_2->setScene(scene2);
// 初始化日志模型
m_logModel = new QStringListModel(this);
ui->detect_log->setModel(m_logModel);
// 注册自定义类型,使其能够在信号槽中跨线程传递
qRegisterMetaType<DetectionResult>("DetectionResult");
qRegisterMetaType<WorkStatus>("WorkStatus");
qRegisterMetaType<TargetPosition>("TargetPosition");
// 连接工作状态更新信号槽
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);
// 初始化右键菜单
setupContextMenu();
updateStatusLog(tr("设备开始初始化..."));
// 初始化模块
Init();
}
MainWindow::~MainWindow()
{
// 释放业务逻辑处理类
if (m_presenter) {
delete m_presenter;
m_presenter = nullptr;
}
delete ui;
}
void MainWindow::updateStatusLog(const QString& message)
{
// 更新状态栏
// statusBar()->showMessage(message);
// 通过信号槽机制更新detect_log控件
emit logUpdateRequested(message);
}
void MainWindow::clearDetectionLog()
{
// 通过信号槽机制清空日志
emit logClearRequested();
}
void MainWindow::Init()
{
// 创建业务逻辑处理类
m_presenter = new LapWeldPresenter();
// 设置状态回调接口
m_presenter->SetStatusCallback(this);
m_deviceStatusWidget = new devstatus(); //因为初始化回调的数据要存储所以要在init前创建好
// 连接devstatus的相机点击信号到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);
#if 0
// 完全禁用拖拽和移动功能
ui->detect_result_list->setDragDropMode(QAbstractItemView::NoDragDrop);
ui->detect_result_list->setDragEnabled(false);
ui->detect_result_list->setAcceptDrops(false);
ui->detect_result_list->setDefaultDropAction(Qt::IgnoreAction);
ui->detect_result_list->setMovement(QListView::Static); // 禁止项目移动
// 设置选择模式但禁用多选
ui->detect_result_list->setSelectionMode(QAbstractItemView::SingleSelection);
ui->detect_result_list->setSelectionBehavior(QAbstractItemView::SelectItems);
// 确保滚动功能正常工作
ui->detect_result_list->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
ui->detect_result_list->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
#endif
// 初始化期间禁用所有功能按钮
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();
// 设置item间距和流向gridSize现在在布局调整函数中动态设置
int itemSpacing = 0;
ui->detect_result_list->setSpacing(itemSpacing); // 设置item间距为0px
// 获取当前的gridSize由布局调整函数设置
QSize currentGridSize = ui->detect_result_list->gridSize();
int gridWidth = currentGridSize.width();
int gridHeight = currentGridSize.height();
int targetIndex = 1;
for (const auto& position : result.positions) {
// 创建自定义的ResultItem widget
ResultItem* resultWidget = new ResultItem();
// 设置widget的autoFillBackground属性确保背景色生效
resultWidget->setAutoFillBackground(true);
// 设置检测结果数据直接使用TargetPosition
resultWidget->setResultData(targetIndex, position);
// 创建QListWidgetItem
QListWidgetItem* item = new QListWidgetItem();
// 设置item背景为透明让自定义widget的背景显示出来
item->setBackground(QBrush(Qt::transparent));
// 设置item的大小提示 - 应该与gridSize一致
item->setSizeHint(QSize(gridWidth, gridHeight));
// 确保每个item都不能被拖动
item->setFlags(item->flags() & ~Qt::ItemIsDragEnabled & ~Qt::ItemIsDropEnabled);
// 将item添加到列表
ui->detect_result_list->addItem(item);
// 将自定义widget设置为item的显示内容
ui->detect_result_list->setItemWidget(item, resultWidget);
targetIndex++;
}
}
// 状态更新槽函数
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)
{
// 通过信号槽机制更新UI确保在主线程中执行
emit detectionResultUpdateRequested(result);
}
void MainWindow::OnCamera1StatusChanged(bool isConnected)
{
// 直接更新设备状态widget
if (m_deviceStatusWidget) {
m_deviceStatusWidget->updateCamera1Status(isConnected);
}
}
// 相机2状态更新槽函数
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);
}
}
}
// 根据相机个数调整页面布局
adjustLayoutForCameraCount(cameraCount);
// 如果只有一个相机,更新状态消息
if (cameraCount < 2) {
// 更新状态消息
updateStatusLog(tr("系统使用单相机模式"));
} else {
// 更新状态消息
updateStatusLog(tr("系统使用双相机模式"));
}
}
// 机械臂状态更新槽函数
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::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 DetectionResult& result)
{
// 根据相机索引决定显示在哪个图像视图上
if (result.cameraIndex == 2) {
// 第二个相机的结果显示在detect_image_2上
updateDetectionLog(tr("相机2检测结果更新"));
displayImageInSecondView(result.image);
} else {
// 第一个相机或默认显示在detect_image上
updateDetectionLog(tr("相机1检测结果更新"));
displayImage(result.image);
}
// 更新检测结果到列表
addDetectionResult(result);
}
void MainWindow::updateDetectionLog(const QString& message)
{
// 在UI线程中更新detect_log控件QListView
if (!m_logModel) return ;
// 添加时间戳(包含年月日)
// QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss");
QString logEntry = QString("[%1] %2").arg(timestamp).arg(message);
// 获取当前数据
QStringList logList = m_logModel->stringList();
// 添加新的日志条目
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());
}
}
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);
// 使用新的相机列表获取功能
// 如果对话框不存在创建新的DialogCamera
if (nullptr == ui_dialogCamera) {
ui_dialogCamera = new DialogCamera(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);
// 获取配置对象
IVrConfig* config = m_presenter->GetConfig();
if (!config) {
// 恢复按钮状态
setButtonSelectedState(ui->btn_algo_config, false);
// 设置白色字体的警告消息框
QMessageBox msgBox;
msgBox.setWindowTitle("错误");
msgBox.setText("配置模块未正确初始化!");
msgBox.setIcon(QMessageBox::Warning);
msgBox.setStyleSheet("QMessageBox { color: white; }");
msgBox.exec();
return;
}
if(nullptr == ui_dialogConfig){
ui_dialogConfig = new DialogAlgoarg(config, this);
// 连接对话框关闭信号
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;
}
// 检查Presenter是否已初始化
if (!m_presenter) {
updateStatusLog(tr("系统未初始化,请等待初始化完成"));
return;
}
// 设置当前按钮为选中状态
setButtonSelectedState(ui->btn_camera_levelling, true);
if(nullptr == ui_dialogCameraLevel){
ui_dialogCameraLevel = new DialogCameraLevel(this);
// 连接对话框关闭信号
connect(ui_dialogCameraLevel, &QDialog::finished, this, [this]() {
setButtonSelectedState(ui->btn_camera_levelling, false);
});
}
// 设置相机列表和presenter到对话框
ui_dialogCameraLevel->setCameraList(m_presenter->GetCameraList(), 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);
// if (ui->btn_test) ui->btn_test->setEnabled(enabled);
// 窗口控制按钮(最小化和关闭)始终可用
// if (ui->btn_hide) ui->btn_hide->setEnabled(true);
// if (ui->btn_close) ui->btn_close->setEnabled(true);
}
// 设置按钮图像
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 = ":/resource/config_camera.png";
selectedImage = ":/resource/config_camera_s.png";
} else if (button == ui->btn_algo_config) {
normalImage = ":/resource/config_algo.png";
selectedImage = ":/resource/config_algo_s.png";
} else if (button == ui->btn_camera_levelling) {
normalImage = ":/resource/config_camera_level.png";
selectedImage = ":/resource/config_camera_level_s.png";
} else if (button == ui->btn_test) {
normalImage = ":/resource/config_data_test.png";
selectedImage = ":/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<QPushButton*> 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::adjustLayoutForCameraCount(int cameraCount)
{
if (cameraCount <= 1) {
// 单相机模式布局
setupSingleCameraLayout();
} else {
// 多相机模式布局
setupMultiCameraLayout();
}
}
// 设置单相机模式布局
void MainWindow::setupSingleCameraLayout()
{
// 单相机模式下的原始布局
// detect_image: 占据左侧大部分空间
ui->detect_image->setGeometry(20, 140, 1311, 890);
// detect_image_2: 隐藏
ui->detect_image_2->setVisible(false);
// 设备状态框架: 位于右上方,恢复原始尺寸
ui->frame_dev->setGeometry(1344, 140, 556, 64);
// 检测结果列表: 位于右侧中间
ui->detect_result_list->setGeometry(1344, 216, 556, 622);
// 单相机模式下恢复原有的垂直滚动设置
ui->detect_result_list->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
ui->detect_result_list->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
ui->detect_result_list->setFlow(QListView::LeftToRight); // 从左到右排列
ui->detect_result_list->setWrapping(true); // 允许换行
// 单相机模式设置gridSizegridHeight = 207
int gridWidth = 275;
int gridHeight = 206;
ui->detect_result_list->setGridSize(QSize(gridWidth, gridHeight));
// 恢复设备状态widget的原始布局
m_deviceStatusWidget->setCameraCount(1);
// 日志: 位于右下方
ui->detect_log->setGeometry(1344, 850, 556, 176);
updateStatusLog(tr("页面布局已调整为单相机模式"));
}
// 设置多相机模式布局
void MainWindow::setupMultiCameraLayout()
{
// 多相机模式下的布局调整
// detect_image: 缩小到左侧一半空间
ui->detect_image->setGeometry(10, 140, 940, 660);
// detect_image_2: 显示在右侧一半空间
ui->detect_image_2->setVisible(true);
ui->detect_image_2->setGeometry(970, 140, 940, 660);
// 设备状态框架: 移动到下方左侧,调整为更高的尺寸以适应纵向排布
ui->frame_dev->setGeometry(10, 806, 180, 200);
// 检测结果列表: 移动到下方中间
ui->detect_result_list->setGeometry(196, 806, 1380, 200);
// 多相机模式设置gridSizegridHeight = 200
int gridWidth = 230;
int gridHeight = 190;
ui->detect_result_list->setGridSize(QSize(gridWidth, gridHeight));
m_deviceStatusWidget->setCameraCount(2);
// 日志: 移动到下方右侧
ui->detect_log->setGeometry(1582, 806, 328, 200);
updateStatusLog(tr("页面布局已调整为多相机模式"));
}
// 处理相机点击事件
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_saveDataAction->setIcon(QIcon(":/resource/save.png")); // 如果有保存图标的话
// 设置右键菜单的样式表,使菜单项默认显示为灰色
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 {
// 直接调用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;
}
}