GrabBag/GrabBagApp/mainwindow.cpp

549 lines
17 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"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
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(GetGrabBagFullVersion())
.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);
// 初始化GraphicsScene
QGraphicsScene* scene = new QGraphicsScene(this);
ui->detect_image->setScene(scene);
// 初始化日志模型
m_logModel = new QStringListModel(this);
ui->detect_log->setModel(m_logModel);
// 原有的状态指示器已删除状态显示统一在devstatus中处理
// 注册自定义类型,使其能够在信号槽中跨线程传递
qRegisterMetaType<DetectionResult>("DetectionResult");
qRegisterMetaType<WorkStatus>("WorkStatus");
qRegisterMetaType<GrabBagPosition>("GrabBagPosition");
qRegisterMetaType<GrabBagPositionLayout>("GrabBagPositionLayout");
// 连接工作状态更新信号槽
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);
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 GrabBagPresenter();
// 设置状态回调接口
m_presenter->SetStatusCallback(this);
m_deviceStatusWidget = new devstatus(); //因为初始化回调的数据要存储所以要在init前创建好
// 将设备状态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::ScrollBarAlwaysOn);
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::addDetectionResult(const DetectionResult& result)
{
// 清空之前的所有检测结果数据
ui->detect_result_list->clear();
// 设置为图标模式,实现网格布局(多列显示)
ui->detect_result_list->setViewMode(QListView::IconMode);
ui->detect_result_list->setResizeMode(QListView::Adjust);
// 设置滚动条策略:强制隐藏所有滚动条
ui->detect_result_list->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
ui->detect_result_list->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
// 计算gridWidth考虑12px间距确保两列布局
int totalWidth = ui->detect_result_list->width();
int totalHeight = ui->detect_result_list->height();
int itemSpacing = 0;
int gridWidth = (totalWidth - 20) / 2; //20是滚动条的宽度
int gridHeight = totalHeight / 3 - 1;
LOG_DEBUG("totalWidth: %d, totalHeight: %d, gridWidth: %d, gridHeight: %d", totalWidth, totalHeight, gridWidth, gridHeight);
ui->detect_result_list->setGridSize(QSize(gridWidth, gridHeight)); // 设置每个格子的大小
ui->detect_result_list->setSpacing(itemSpacing); // 设置item间距为12px
ui->detect_result_list->setFlow(QListView::LeftToRight); // 从左到右排列
ui->detect_result_list->setWrapping(true); // 允许换行
auto layoutIter = result.positionLayout.begin();
int targetIndex = 1;
while(layoutIter != result.positionLayout.end())
{
auto positionIter = layoutIter->position.begin();
while(positionIter != layoutIter->position.end())
{
// 创建自定义的ResultItem widget
ResultItem* resultWidget = new ResultItem();
// 设置widget的autoFillBackground属性确保背景色生效
resultWidget->setAutoFillBackground(true);
// 设置检测结果数据直接使用GrabBagPosition
resultWidget->setResultData(targetIndex, *positionIter);
// 创建QListWidgetItem
QListWidgetItem* item = new QListWidgetItem();
// 设置item背景为透明让自定义widget的背景显示出来
item->setBackground(QBrush(Qt::transparent));
// 设置item的大小提示 - 应该与gridSize一致
item->setSizeHint(QSize(gridWidth, gridHeight));
// 将item添加到列表
ui->detect_result_list->addItem(item);
// 将自定义widget设置为item的显示内容
ui->detect_result_list->setItemWidget(item, resultWidget);
targetIndex++;
positionIter++;
}
layoutIter++;
}
}
// 状态更新槽函数
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 (cameraCount < 2) {
// 更新状态消息
updateStatusLog(tr("系统使用单相机模式"));
} else {
// 更新状态消息
updateStatusLog(tr("系统使用双相机模式"));
}
}
// 机械臂状态更新槽函数
void MainWindow::OnRobotConnectionChanged(bool isConnected)
{
// 直接更新设备状态widget
if (m_deviceStatusWidget) {
m_deviceStatusWidget->updateRobotStatus(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) {
ui->label_work->setText(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)
{
// 显示检测图像
updateDetectionLog(tr("检测结果图像更新"));
displayImage(result.image);
// 更新检测结果到列表
updateDetectionLog(tr("检测结果列表更新"));
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 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()
{
// 检查Presenter是否已初始化
if (!m_presenter) {
updateStatusLog(tr("系统未初始化,请等待初始化完成"));
return;
}
// 使用新的相机列表获取功能
std::vector<IVrEyeDevice*> availableCameras;
std::vector<QString> cameraNames;
// 获取相机列表和名称
m_presenter->GetCameraListWithNames(availableCameras, cameraNames);
// 如果对话框不存在创建新的DialogCamera
if (nullptr == ui_dialogCamera) {
ui_dialogCamera = new DialogCamera(availableCameras, cameraNames, this);
}
ui_dialogCamera->show();
}
void MainWindow::on_btn_algo_config_clicked()
{
// 检查Presenter是否已初始化
if (!m_presenter) {
updateStatusLog(tr("系统未初始化,请等待初始化完成"));
return;
}
// 获取配置对象
IVrConfig* config = m_presenter->GetConfig();
if (!config) {
// 设置白色字体的警告消息框
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 DialogConfig(config, this);
}
ui_dialogConfig->show();
}
void MainWindow::on_btn_camera_levelling_clicked()
{
if(nullptr == ui_dialogCameraLevel){
ui_dialogCameraLevel = new DialogCameraLevel(this);
}
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()
{
// 打开文件选择对话框
QString fileName = QFileDialog::getOpenFileName(
this,
tr("选择调试数据文件"),
QString(),
tr("激光数据文件 (*.txt);;所有文件 (*.*)")
);
if (fileName.isEmpty()) {
// 用户取消了文件选择
return;
}
// 检查Presenter是否已初始化
if (!m_presenter) {
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);
QMessageBox::warning(this, tr("错误"), errorMsg);
}
});
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);
}