GrabBag/Tools/ControlApp/mainwindow.cpp
2026-03-11 23:40:06 +08:00

485 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 <QMessageBox>
#include <QDebug>
#include <QScreen>
#include <QApplication>
#include <QLabel>
#include <QMouseEvent>
#include <QSizeGrip>
#include <QSettings>
#include <QCoreApplication>
#include <QTimer>
#include "Version.h"
#include "StyledMessageBox.h"
#include "DialogConfig.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 设置窗口图标
#ifdef _WIN32
this->setWindowIcon(QIcon(":/resource/logo.ico"));
#else
this->setWindowIcon(QIcon(":/resource/logo.png"));
#endif
// 隐藏标题栏
setWindowFlags(Qt::FramelessWindowHint);
// 设置状态栏
QFont statusFont = statusBar()->font();
statusFont.setPointSize(12);
statusBar()->setFont(statusFont);
statusBar()->setStyleSheet("QStatusBar { color: rgb(239, 241, 245); padding: 20px; }");
// 添加版本信息到状态栏(只显示版本号)
QString versionText = QString("%1").arg(GetControlVersionOnly());
QLabel* versionLabel = new QLabel(versionText);
versionLabel->setStyleSheet("color: rgb(239, 241, 245); font-size: 20px;");
statusBar()->addPermanentWidget(versionLabel);
// 设置窗口大小为1200x700不自动最大化
this->resize(1200, 700);
this->setMinimumSize(1200, 700); // 设置最小尺寸
// 安装事件过滤器到顶部groupBox用于拖动窗口
ui->groupBox->installEventFilter(this);
// 初始化工作流程显示组件
m_workflowWidget = new WorkflowWidget(this);
QVBoxLayout* workflowLayout = new QVBoxLayout(ui->frame_workflow);
workflowLayout->setContentsMargins(0, 0, 0, 0);
workflowLayout->addWidget(m_workflowWidget);
// 初始化设备状态显示组件
m_deviceStatusWidget = new DeviceStatusWidget(this);
m_deviceStatusWidget->setCameraCount(1); // 显示1个相机用于显示控制器状态
m_deviceStatusWidget->setCamera1Name("控制器");
m_deviceStatusWidget->setCameraClickable(false); // 控制器不可点击
QVBoxLayout* deviceLayout = new QVBoxLayout(ui->frame_device);
deviceLayout->setContentsMargins(0, 0, 0, 0);
deviceLayout->addWidget(m_deviceStatusWidget);
// 初始化日志辅助类
m_logHelper = new DetectLogHelper(ui->detect_log, this);
// 创建Presenter
m_presenter = new DemoControlPresenter(this);
// 连接信号槽
connect(m_presenter, &DemoControlPresenter::statusMessageUpdated,
this, &MainWindow::onStatusMessageUpdated);
connect(m_presenter, &DemoControlPresenter::workflowStepChanged,
this, &MainWindow::onWorkflowStepChanged);
connect(m_presenter, &DemoControlPresenter::controllerConnectionChanged,
this, &MainWindow::onControllerConnectionChanged);
connect(m_presenter, &DemoControlPresenter::robotConnectionChanged,
this, &MainWindow::onRobotConnectionChanged);
connect(m_presenter, &DemoControlPresenter::detectionResultUpdated,
this, &MainWindow::onDetectionResultUpdated);
// 初始化按钮状态
ui->btn_pause->setEnabled(false);
ui->btn_step->setEnabled(true);
// 初始化
Init();
}
MainWindow::~MainWindow()
{
if (m_presenter) {
delete m_presenter;
m_presenter = nullptr;
}
delete ui;
}
void MainWindow::Init()
{
updateStatusLog("主控程序初始化中...");
// 在线程中执行初始化
std::thread initThread([this]() {
int result = m_presenter->Init();
if (result != 0) {
updateStatusLog(QString("初始化失败,错误码:%1").arg(result));
} else {
updateStatusLog("系统初始化完成");
}
// 从配置文件加载配置
QMetaObject::invokeMethod(this, [this]() {
// 加载配置到Presenter
DialogConfig::LoadConfigToPresenter(m_presenter);
updateStatusLog("配置已加载");
// 从配置文件读取连接参数
QSettings settings(DialogConfig::GetConfigFilePath(), QSettings::IniFormat);
QString controllerIP = settings.value("Controller/IP", "192.168.0.88").toString();
int controllerPort = settings.value("Controller/Port", 502).toInt();
QString robotIP = settings.value("Robot/IP", "192.168.58.2").toString();
updateStatusLog(QString("正在连接控制器 %1:%2...").arg(controllerIP).arg(controllerPort));
m_presenter->ConnectToController(controllerIP, controllerPort);
updateStatusLog(QString("正在连接机械臂 %1...").arg(robotIP));
m_presenter->ConnectToRobot(robotIP);
}, Qt::QueuedConnection);
});
initThread.detach();
}
void MainWindow::updateStatusLog(const QString& message)
{
if (m_logHelper) {
m_logHelper->appendLog(message);
}
}
void MainWindow::on_btn_start_clicked()
{
if (!m_presenter) {
updateStatusLog("系统未初始化");
return;
}
if (!m_presenter->IsControllerConnected()) {
StyledMessageBox::warning(this, "警告", "控制器未连接,无法启动工作流程");
return;
}
if (!m_presenter->IsRobotConnected()) {
StyledMessageBox::warning(this, "警告", "机械臂未连接,无法启动工作流程");
return;
}
updateStatusLog("启动工作流程...");
m_presenter->StartWorkflow();
// 更新按钮状态:连续执行模式
ui->btn_start->setEnabled(false);
ui->btn_pause->setEnabled(true);
ui->btn_pause->setText("暂停");
ui->btn_step->setEnabled(false); // 连续执行时禁用单步
}
void MainWindow::on_btn_stop_clicked()
{
if (!m_presenter) {
updateStatusLog("系统未初始化");
return;
}
updateStatusLog("停止工作流程...");
m_presenter->StopWorkflow();
m_workflowWidget->reset();
// 更新按钮状态:停止后恢复初始状态
ui->btn_start->setEnabled(true);
ui->btn_pause->setEnabled(false);
ui->btn_pause->setText("暂停");
ui->btn_step->setEnabled(true);
}
void MainWindow::on_btn_pause_clicked()
{
if (!m_presenter) {
updateStatusLog("系统未初始化");
return;
}
if (m_presenter->IsWorkflowPaused()) {
// 当前是暂停状态,点击恢复
updateStatusLog("恢复工作流程...");
m_presenter->ResumeWorkflow();
ui->btn_pause->setText("暂停");
ui->btn_step->setEnabled(false); // 恢复后禁用单步
ui->btn_start->setEnabled(false); // 恢复后禁用开始
} else {
// 当前是运行状态,点击暂停
updateStatusLog("暂停工作流程...");
m_presenter->PauseWorkflow();
ui->btn_pause->setText("继续");
ui->btn_step->setEnabled(true); // 暂停后启用单步
ui->btn_start->setEnabled(false); // 暂停时仍然禁用开始
}
}
void MainWindow::on_btn_step_clicked()
{
if (!m_presenter) {
updateStatusLog("系统未初始化");
return;
}
if (!m_presenter->IsControllerConnected()) {
StyledMessageBox::warning(this, "警告", "控制器未连接,无法执行单步");
return;
}
if (!m_presenter->IsRobotConnected()) {
StyledMessageBox::warning(this, "警告", "机械臂未连接,无法执行单步");
return;
}
updateStatusLog("执行单步...");
m_presenter->StepWorkflow();
// 更新按钮状态
if (!m_presenter->IsWorkflowRunning()) {
// 首次单步,启动工作流程
ui->btn_start->setEnabled(false);
ui->btn_pause->setEnabled(true);
ui->btn_pause->setText("继续");
}
}
void MainWindow::on_btn_config_clicked()
{
if (!m_presenter) {
updateStatusLog("系统未初始化");
return;
}
if (!m_dialogConfig) {
m_dialogConfig = new DialogConfig(m_presenter, this);
}
m_dialogConfig->exec();
}
void MainWindow::on_btn_fullscreen_clicked()
{
if (m_isFullScreen) {
// 退出全屏,恢复到正常窗口
setWindowFlags(Qt::FramelessWindowHint);
setGeometry(m_normalGeometry);
showNormal();
m_isFullScreen = false;
updateStatusLog("退出全屏");
} else {
// 进入全屏
m_normalGeometry = geometry();
setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
showFullScreen();
m_isFullScreen = true;
updateStatusLog("进入全屏");
}
}
void MainWindow::on_btn_hide_clicked()
{
this->showMinimized();
}
void MainWindow::on_btn_close_clicked()
{
this->close();
}
void MainWindow::onStatusMessageUpdated(const QString& message)
{
updateStatusLog(message);
}
void MainWindow::onWorkflowStepChanged(WorkflowStep step, const QString& message)
{
m_workflowWidget->updateStep(step);
updateStatusLog(message);
// 如果工作流程完成,检查是否真的结束了
if (step == WorkflowStep::Completed) {
// 延迟检查工作流程是否真的停止
QTimer::singleShot(100, this, [this]() {
if (!m_presenter->IsWorkflowRunning()) {
// 工作流程已停止,更新按钮状态
ui->btn_start->setEnabled(true);
ui->btn_pause->setEnabled(false);
ui->btn_pause->setText("暂停");
ui->btn_step->setEnabled(true);
} else if (m_presenter->IsWorkflowStepMode()) {
// 单步模式下完成一轮,保持"继续"按钮状态不变
// 按钮应该显示"继续",因为处于单步等待状态
ui->btn_pause->setText("继续");
}
});
} else if (step == WorkflowStep::Error) {
// 出错时立即更新按钮状态
ui->btn_start->setEnabled(true);
ui->btn_pause->setEnabled(false);
ui->btn_pause->setText("暂停");
ui->btn_step->setEnabled(true);
}
}
void MainWindow::onControllerConnectionChanged(bool connected)
{
// 更新设备状态显示使用相机1状态显示控制器连接状态
if (m_deviceStatusWidget) {
m_deviceStatusWidget->updateCamera1Status(connected);
}
if (connected) {
updateStatusLog("控制器已连接");
} else {
updateStatusLog("控制器已断开");
}
}
void MainWindow::onRobotConnectionChanged(bool connected)
{
if (m_deviceStatusWidget) {
m_deviceStatusWidget->updateRobotStatus(connected);
}
if (connected) {
updateStatusLog("机械臂已连接");
} else {
updateStatusLog("机械臂已断开");
}
}
void MainWindow::onDetectionResultUpdated(const DetectionResult& result)
{
m_workflowWidget->updateDetectionResult(result);
}
void MainWindow::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
ResizeRegion region = getResizeRegion(event->pos());
if (region != None) {
// 开始缩放
m_isResizing = true;
m_resizeRegion = region;
m_resizeStartPos = event->globalPos();
m_resizeStartGeometry = this->geometry();
event->accept();
}
}
}
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
if (m_isResizing && (event->buttons() & Qt::LeftButton)) {
// 处理窗口缩放
QPoint delta = event->globalPos() - m_resizeStartPos;
QRect newGeometry = m_resizeStartGeometry;
if (m_resizeRegion & Left) {
newGeometry.setLeft(m_resizeStartGeometry.left() + delta.x());
}
if (m_resizeRegion & Right) {
newGeometry.setRight(m_resizeStartGeometry.right() + delta.x());
}
if (m_resizeRegion & Top) {
newGeometry.setTop(m_resizeStartGeometry.top() + delta.y());
}
if (m_resizeRegion & Bottom) {
newGeometry.setBottom(m_resizeStartGeometry.bottom() + delta.y());
}
// 确保不小于最小尺寸
if (newGeometry.width() >= minimumWidth() && newGeometry.height() >= minimumHeight()) {
this->setGeometry(newGeometry);
}
event->accept();
} else if (!m_isDragging) {
// 更新鼠标光标
ResizeRegion region = getResizeRegion(event->pos());
updateCursor(region);
}
}
void MainWindow::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
m_isResizing = false;
m_resizeRegion = None;
m_isDragging = false;
updateCursor(None);
event->accept();
}
}
MainWindow::ResizeRegion MainWindow::getResizeRegion(const QPoint& pos)
{
int region = None;
if (pos.x() <= RESIZE_BORDER_WIDTH) {
region |= Left;
} else if (pos.x() >= width() - RESIZE_BORDER_WIDTH) {
region |= Right;
}
if (pos.y() <= RESIZE_BORDER_WIDTH) {
region |= Top;
} else if (pos.y() >= height() - RESIZE_BORDER_WIDTH) {
region |= Bottom;
}
return static_cast<ResizeRegion>(region);
}
void MainWindow::updateCursor(ResizeRegion region)
{
switch (region) {
case TopLeft:
case BottomRight:
setCursor(Qt::SizeFDiagCursor);
break;
case TopRight:
case BottomLeft:
setCursor(Qt::SizeBDiagCursor);
break;
case Left:
case Right:
setCursor(Qt::SizeHorCursor);
break;
case Top:
case Bottom:
setCursor(Qt::SizeVerCursor);
break;
default:
setCursor(Qt::ArrowCursor);
break;
}
}
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
// 只在顶部groupBox区域允许拖动
if (obj == ui->groupBox) {
if (event->type() == QEvent::MouseButtonPress) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
if (mouseEvent->button() == Qt::LeftButton) {
m_isDragging = true;
m_dragPosition = mouseEvent->globalPos() - this->frameGeometry().topLeft();
return true;
}
}
else if (event->type() == QEvent::MouseMove) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
if (m_isDragging && (mouseEvent->buttons() & Qt::LeftButton)) {
this->move(mouseEvent->globalPos() - m_dragPosition);
return true;
}
}
else if (event->type() == QEvent::MouseButtonRelease) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
if (mouseEvent->button() == Qt::LeftButton) {
m_isDragging = false;
return true;
}
}
}
return QMainWindow::eventFilter(obj, event);
}