GrabBag/Tools/ControlApp/mainwindow.cpp

485 lines
15 KiB
C++
Raw Normal View History

2026-03-01 18:11:32 +08:00
#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("配置已加载");
// 从配置文件读取连接参数
2026-03-11 23:40:06 +08:00
QSettings settings(DialogConfig::GetConfigFilePath(), QSettings::IniFormat);
2026-03-01 18:11:32 +08:00
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);
}