420 lines
13 KiB
C++
Raw Normal View History

2025-12-10 00:01:32 +08:00
#include "mainwindow.h"
#include "ui_mainwindow.h"
2025-12-27 09:34:02 +08:00
#include <QDebug>
#include <QMessageBox>
#include <QThread>
2025-12-10 00:01:32 +08:00
#include <QDateTime>
2025-12-27 09:34:02 +08:00
#include <QTextCursor>
#include <QStringListModel>
#include "VrLog.h"
2025-12-10 00:01:32 +08:00
#include <QMetaType>
2025-12-27 09:34:02 +08:00
#include <QLabel>
#include <QVBoxLayout>
#include "WorkpiecePositionPresenter.h"
2025-12-10 00:01:32 +08:00
2025-12-27 09:34:02 +08:00
#include "Version.h"
#include "IVrUtils.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
2025-12-10 00:01:32 +08:00
{
ui->setupUi(this);
2025-12-27 09:34:02 +08:00
// 设置窗口图标Windows使用.ico格式
#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);
// 设置状态栏颜色和padding
statusBar()->setStyleSheet("QStatusBar { color: rgb(239, 241, 245); padding: 20px; }");
// 在状态栏右侧添加版本信息(包含编译时间)
QString versionWithBuildTime = QString("%1_%2%3%4%5%6%7")
.arg(GetWorkpiecePositionFullVersion())
.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);
// 初始化日志模型
2025-12-10 00:01:32 +08:00
m_logModel = new QStringListModel(this);
2025-12-27 09:34:02 +08:00
ui->detect_log->setModel(m_logModel);
2025-12-10 00:01:32 +08:00
2025-12-27 09:34:02 +08:00
// 注册自定义类型,使其能够在信号槽中跨线程传递
2025-12-10 00:01:32 +08:00
qRegisterMetaType<WorkpiecePositionDetectionResult>("WorkpiecePositionDetectionResult");
qRegisterMetaType<WorkStatus>("WorkStatus");
qRegisterMetaType<WorkpieceCenterPosition>("WorkpieceCenterPosition");
2025-12-27 09:34:02 +08:00
// 连接工作状态更新信号槽
2025-12-10 00:01:32 +08:00
connect(this, &MainWindow::workStatusUpdateRequested, this, &MainWindow::updateWorkStatusLabel);
2025-12-27 09:34:02 +08:00
// 连接检测结果更新信号槽
2025-12-10 00:01:32 +08:00
connect(this, &MainWindow::detectionResultUpdateRequested, this, &MainWindow::updateDetectionResultDisplay);
2025-12-27 09:34:02 +08:00
// 连接日志更新信号槽
2025-12-10 00:01:32 +08:00
connect(this, &MainWindow::logUpdateRequested, this, &MainWindow::updateDetectionLog);
2025-12-27 09:34:02 +08:00
// 连接清空日志信号槽
connect(this, &MainWindow::logClearRequested, this, &MainWindow::clearDetectionLogUI);
updateStatusLog(tr("设备开始初始化..."));
// 初始化模块
2025-12-10 00:01:32 +08:00
Init();
}
MainWindow::~MainWindow()
{
2025-12-27 09:34:02 +08:00
// 设置退出标志
m_bExiting = true;
LOG_DEBUG("release mainwindow \n");
// 等待初始化线程完成
if (m_initThread.joinable()) {
m_initThread.join();
}
// 释放业务逻辑处理类
if (m_presenter) {
delete m_presenter;
m_presenter = nullptr;
}
LOG_DEBUG("release persenter success \n");
2025-12-10 00:01:32 +08:00
delete ui;
}
2025-12-27 09:34:02 +08:00
void MainWindow::updateStatusLog(const QString& message)
{
// 更新状态栏
// statusBar()->showMessage(message);
// 通过信号槽机制更新detect_log控件
emit logUpdateRequested(message);
}
void MainWindow::clearDetectionLog()
{
// 通过信号槽机制清空日志
emit logClearRequested();
}
2025-12-10 00:01:32 +08:00
void MainWindow::Init()
{
2025-12-27 09:34:02 +08:00
// 创建业务逻辑处理类
2025-12-10 00:01:32 +08:00
m_presenter = new WorkpiecePositionPresenter();
2025-12-27 09:34:02 +08:00
// 设置状态回调接口使用BasePresenter的模板方法
m_presenter->SetStatusCallback<IYWorkpiecePositionStatus>(this);
m_deviceStatusWidget = new DeviceStatusWidget(); //因为初始化回调的数据要存储所以要在init前创建好
// 将设备状态widget添加到frame_dev中
QVBoxLayout* frameDevLayout = new QVBoxLayout(ui->frame_dev);
frameDevLayout->setContentsMargins(0, 0, 0, 0);
frameDevLayout->addWidget(m_deviceStatusWidget);
// 初始化期间禁用所有功能按钮
setButtonsEnabled(false);
// 在线程中执行初始化业务逻辑
m_initThread = std::thread([this]() {
if (m_bExiting) return; // 检查退出标志
updateStatusLog(tr("正在初始化系统..."));
if (m_bExiting) return; // 检查退出标志
int result = m_presenter->Init();
if (m_bExiting) return; // 检查退出标志
if (result != 0) {
updateStatusLog(tr("初始化失败,错误码:%1").arg(result));
} else {
updateStatusLog(tr("系统初始化完成"));
}
});
}
// 添加扩展版本的检测结果函数
void MainWindow::addDetectionResult(const WorkpiecePositionDetectionResult& result)
{
// 清空之前的所有检测结果数据
ui->detect_result_list->clear();
QString resultText;
// 添加每个工件位置信息
for (size_t i = 0; i < result.positions.size(); i++) {
const auto& pos = result.positions[i];
resultText += QString("工件%1: X=%2, Y=%3, Z=%4\n")
.arg(i + 1)
.arg(pos.x, 0, 'f', 2)
.arg(pos.y, 0, 'f', 2)
.arg(pos.z, 0, 'f', 2);
resultText += QString(" Roll=%1, Pitch=%2, Yaw=%3\n")
.arg(pos.roll, 0, 'f', 2)
.arg(pos.pitch, 0, 'f', 2)
.arg(pos.yaw, 0, 'f', 2);
}
// 添加Mark点信息
if (!result.marks.empty()) {
resultText += QString("\nMark点数量: %1\n").arg(result.marks.size());
}
// 创建一个QLabel来显示文本
QLabel* resultLabel = new QLabel(resultText);
resultLabel->setStyleSheet("color: rgb(239, 241, 245); font-size: 12pt; padding: 10px;");
resultLabel->setWordWrap(true);
QListWidgetItem* item = new QListWidgetItem();
item->setSizeHint(resultLabel->sizeHint());
ui->detect_result_list->addItem(item);
ui->detect_result_list->setItemWidget(item, resultLabel);
}
// 状态更新槽函数
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 WorkpiecePositionDetectionResult& result)
{
// 通过信号槽机制更新UI确保在主线程中执行
emit detectionResultUpdateRequested(result);
}
// BinocularMark连接状态更新
void MainWindow::OnBinocularMarkConnectionChanged(bool isConnected)
{
// 更新设备状态widget
if (m_deviceStatusWidget) {
m_deviceStatusWidget->updateCamera1Status(isConnected);
}
}
// EpicEye连接状态更新
void MainWindow::OnEpicEyeConnectionChanged(bool isConnected)
{
// 更新设备状态widget
if (m_deviceStatusWidget) {
m_deviceStatusWidget->updateCamera2Status(isConnected);
}
}
// 实现基类的纯虚函数(映射到具体设备)
void MainWindow::OnCamera1StatusChanged(bool isConnected)
{
OnBinocularMarkConnectionChanged(isConnected);
2025-12-10 00:01:32 +08:00
}
2025-12-27 09:34:02 +08:00
void MainWindow::OnCamera2StatusChanged(bool isConnected)
{
OnEpicEyeConnectionChanged(isConnected);
}
void MainWindow::OnRobotConnectionChanged(bool isConnected)
{
// WorkpiecePositionApp 不使用机械臂,忽略
}
void MainWindow::OnSerialConnectionChanged(bool isConnected)
{
// WorkpiecePositionApp 不使用串口,忽略
}
void MainWindow::OnCameraCountChanged(int cameraCount)
{
// WorkpiecePositionApp 使用固定的两个传感器设备,忽略
}
// 工作状态更新槽函数
void MainWindow::OnWorkStatusChanged(WorkStatus status)
{
// 通过信号槽机制更新UI确保在主线程中执行
emit workStatusUpdateRequested(status);
}
2025-12-10 00:01:32 +08:00
void MainWindow::updateWorkStatusLabel(WorkStatus status)
{
2025-12-27 09:34:02 +08:00
// 如果状态变为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;
}
2025-12-10 00:01:32 +08:00
}
void MainWindow::updateDetectionResultDisplay(const WorkpiecePositionDetectionResult& result)
{
2025-12-27 09:34:02 +08:00
// 更新日志
updateDetectionLog(tr("检测结果更新"));
// 更新检测结果到列表
addDetectionResult(result);
2025-12-10 00:01:32 +08:00
}
void MainWindow::updateDetectionLog(const QString& message)
{
2025-12-27 09:34:02 +08:00
// 在UI线程中更新detect_log控件QListView
2025-12-10 00:01:32 +08:00
if (!m_logModel) return;
2025-12-27 09:34:02 +08:00
// 获取当前数据
QStringList logList = m_logModel->stringList();
// 检查是否与最后一条消息相同
if (message == m_lastLogMessage && !logList.isEmpty()) {
// 相同消息,增加计数并替换最后一条
m_lastLogCount++;
// 添加时间戳
QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss");
QString logEntry = QString("[%1] %2 (x%3)").arg(timestamp).arg(message).arg(m_lastLogCount);
// 替换最后一条
logList[logList.size() - 1] = logEntry;
} else {
// 新消息,重置计数
m_lastLogMessage = message;
m_lastLogCount = 1;
// 添加时间戳
QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss");
QString logEntry = QString("[%1] %2").arg(timestamp).arg(message);
// 添加新的日志条目
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());
}
// 重置日志计数器
m_lastLogMessage.clear();
m_lastLogCount = 0;
2025-12-10 00:01:32 +08:00
}
2025-12-27 09:34:02 +08:00
void MainWindow::on_btn_start_clicked()
{
// 检查Presenter是否已初始化
if (!m_presenter) {
updateStatusLog(tr("系统未初始化,请等待初始化完成"));
return;
}
// 清空检测日志,开始新的检测
clearDetectionLog();
2025-12-10 00:01:32 +08:00
2025-12-27 09:34:02 +08:00
// 使用Presenter启动检测
m_presenter->StartDetection();
}
void MainWindow::on_btn_stop_clicked()
2025-12-10 00:01:32 +08:00
{
2025-12-27 09:34:02 +08:00
// 检查Presenter是否已初始化
if (!m_presenter) {
updateStatusLog(tr("系统未初始化,请等待初始化完成"));
return;
2025-12-10 00:01:32 +08:00
}
2025-12-27 09:34:02 +08:00
m_presenter->StopDetection();
}
void MainWindow::on_btn_hide_clicked()
{
// 最小化窗口
this->showMinimized();
}
void MainWindow::on_btn_close_clicked()
{
// 关闭应用程序
this->close();
2025-12-10 00:01:32 +08:00
}
2025-12-27 09:34:02 +08:00
// 设置按钮启用/禁用状态
void MainWindow::setButtonsEnabled(bool enabled)
2025-12-10 00:01:32 +08:00
{
2025-12-27 09:34:02 +08:00
// 功能按钮
if (ui->btn_start) ui->btn_start->setEnabled(enabled);
if (ui->btn_stop) ui->btn_stop->setEnabled(enabled);
2025-12-10 00:01:32 +08:00
}