GrabBag/GrabBagApp/mainwindow.cpp

503 lines
15 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 "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();
// 初始化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前创建好
// 初始化业务逻辑
int result = m_presenter->Init();
if (result != 0) {
updateStatusLog(tr("初始化失败,错误码:%1").arg(result));
}
// 初始化完成后在detect_result_list中增加设备状态widget
QListWidgetItem* deviceStatusItem = new QListWidgetItem();
deviceStatusItem->setBackground(QBrush(Qt::transparent));
deviceStatusItem->setSizeHint(QSize(272, 200));
ui->detect_result_list->addItem(deviceStatusItem);
ui->detect_result_list->setItemWidget(deviceStatusItem, 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);
}
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)
{
// 清空之前的数据除了第一个设备状态item
while (ui->detect_result_list->count() > 1) {
QListWidgetItem* item = ui->detect_result_list->takeItem(1);
delete item;
}
// 更新现有设备状态显示第一个item就是设备状态
if (m_deviceStatusWidget) {
// m_deviceStatusWidget会自动从其内部状态获取设备状态信息
// 不需要手动更新因为状态变化时会直接更新到widget中
}
// 设置为图标模式,实现网格布局(多列显示)
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 itemSpacing = 12;
int gridWidth = (totalWidth - itemSpacing - 17) / 2; //20是滚动条的宽度
int gridHeight = 200;
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)
{
LOG_DEBUG("[UI Display] ======== Detection result update.\n");
// 通过信号槽机制更新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;");
break;
case WorkStatus::InitIng:
case WorkStatus::Working:
ui->label_work->setStyleSheet("color: blue;");
break;
case WorkStatus::Completed:
ui->label_work->setStyleSheet("color: green; font-weight: bold;");
break;
case WorkStatus::Error:
ui->label_work->setStyleSheet("color: red; font-weight: bold;");
break;
default:
ui->label_work->setStyleSheet("");
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()
{
// 清空检测日志,开始新的检测
clearDetectionLog();
// 使用Presenter启动检测
if (m_presenter) {
m_presenter->StartDetection();
}
}
void MainWindow::on_btn_stop_clicked()
{
if (m_presenter) {
m_presenter->StopDetection();
}
}
void MainWindow::on_btn_camera_clicked()
{
// 使用新的相机列表获取功能
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()
{
// 获取配置对象
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();
}