#include "DeviceStatusWidget.h" #include "ui_DeviceStatusWidget.h" #include #include #include #include "VrLog.h" DeviceStatusWidget::DeviceStatusWidget(QWidget *parent) : QWidget(parent) , ui(new Ui::DeviceStatusWidget) , m_selectedCameraIndex(0) , m_camera1Name("") , m_camera2Name("") , m_robotVisible(true) , m_cameraCount(1) , m_cameraClickable(true) { ui->setupUi(this); // 强制应用样式表 - 这是关键! this->setAttribute(Qt::WA_StyledBackground, true); // 初始化时设置样式 setItemStyle(); // 初始化点击事件 initClickEvents(); // 初始化设备状态(离线状态) updateCamera1Status(false); updateCamera2Status(false); updateRobotStatus(false); setCameraSelectedStyle(1); } DeviceStatusWidget::~DeviceStatusWidget() { delete ui; } // 设置devstatus的样式 void DeviceStatusWidget::setItemStyle() { this->setStyleSheet( "DeviceStatusWidget { " " border: 2px solid #191A1C; " // 添加边框作为格子间分隔线 " border-radius: 0px; " // 去掉圆角,让分隔线更清晰 "} " ); } // 设置相机状态图片的私有成员函数 void DeviceStatusWidget::setCameraStatusImage(QWidget* widget, bool isOnline) { if (!widget) return; QString imagePath = isOnline ? ":/common/resource/camera_online.png" : ":/common/resource/camera_offline.png"; widget->setStyleSheet(QString("image: url(%1);").arg(imagePath)); // widget->setFixedSize(32, 32); // 调整大小以适应图片 } // 设置机械臂状态图片的私有成员函数 void DeviceStatusWidget::setRobotStatusImage(QWidget* widget, bool isOnline) { if (!widget) return; QString imagePath = isOnline ? ":/common/resource/robot_online.png" : ":/common/resource/robot_offline.png"; widget->setStyleSheet(QString("image: url(%1); ").arg(imagePath)); // widget->setFixedSize(32, 32); // 调整大小以适应图片 } // 设置相机1名称 void DeviceStatusWidget::setCamera1Name(const QString& name) { // 检查是否在主线程中 if (QThread::currentThread() == this->thread()) { // 在主线程中,直接执行 m_camera1Name = name; // 如果相机1已经初始化过状态,则更新显示文本 if (ui->dev_camera_1_txt) { updateCamera1DisplayText(ui->dev_camera_1_txt->text().contains("在线")); } } else { // 在其他线程中,使用队列方式确保线程安全 QMetaObject::invokeMethod(this, [this, name]() { m_camera1Name = name; // 如果相机1已经初始化过状态,则更新显示文本 if (ui->dev_camera_1_txt) { updateCamera1DisplayText(ui->dev_camera_1_txt->text().contains("在线")); } }, Qt::QueuedConnection); } } // 设置相机2名称 void DeviceStatusWidget::setCamera2Name(const QString& name) { // 检查是否在主线程中 if (QThread::currentThread() == this->thread()) { // 在主线程中,直接执行 m_camera2Name = name; // 如果相机2已经初始化过状态,则更新显示文本 if (ui->dev_camera_2_txt) { updateCamera2DisplayText(ui->dev_camera_2_txt->text().contains("在线")); } } else { // 在其他线程中,使用队列方式确保线程安全 QMetaObject::invokeMethod(this, [this, name]() { m_camera2Name = name; // 如果相机2已经初始化过状态,则更新显示文本 if (ui->dev_camera_2_txt) { updateCamera2DisplayText(ui->dev_camera_2_txt->text().contains("在线")); } }, Qt::QueuedConnection); } } // 更新相机1状态 void DeviceStatusWidget::updateCamera1Status(bool isConnected) { // 检查是否在主线程中 if (QThread::currentThread() == this->thread()) { // 在主线程中,直接执行 setCameraStatusImage(ui->dev_camer_1_img, isConnected); updateCamera1DisplayText(isConnected); } else { // 在其他线程中,使用队列方式确保线程安全 QMetaObject::invokeMethod(this, [this, isConnected]() { setCameraStatusImage(ui->dev_camer_1_img, isConnected); updateCamera1DisplayText(isConnected); }, Qt::QueuedConnection); } } // 更新相机2状态 void DeviceStatusWidget::updateCamera2Status(bool isConnected) { // 检查是否在主线程中 if (QThread::currentThread() == this->thread()) { // 在主线程中,直接执行 setCameraStatusImage(ui->dev_camer_2_img, isConnected); updateCamera2DisplayText(isConnected); } else { // 在其他线程中,使用队列方式确保线程安全 QMetaObject::invokeMethod(this, [this, isConnected]() { setCameraStatusImage(ui->dev_camer_2_img, isConnected); updateCamera2DisplayText(isConnected); }, Qt::QueuedConnection); } } // 更新相机1显示文本的私有方法 void DeviceStatusWidget::updateCamera1DisplayText(bool isConnected) { QString statusText; if (m_camera1Name.isEmpty()) { statusText = isConnected ? "相机1在线" : "相机1离线"; } else { statusText = isConnected ? QString("%1在线").arg(m_camera1Name) : QString("%1离线").arg(m_camera1Name); } QString colorStyle = isConnected ? "color: rgb(140, 180, 60);" : "color: rgb(220, 60, 60);"; ui->dev_camera_1_txt->setText(statusText); ui->dev_camera_1_txt->setStyleSheet(colorStyle); } // 更新相机2显示文本的私有方法 void DeviceStatusWidget::updateCamera2DisplayText(bool isConnected) { QString statusText; if (m_camera2Name.isEmpty()) { statusText = isConnected ? "相机2在线" : "相机2离线"; } else { statusText = isConnected ? QString("%1在线").arg(m_camera2Name) : QString("%1离线").arg(m_camera2Name); } QString colorStyle = isConnected ? "color: rgb(140, 180, 60);" : "color: rgb(220, 60, 60);"; ui->dev_camera_2_txt->setText(statusText); ui->dev_camera_2_txt->setStyleSheet(colorStyle); } // 更新机械臂状态 void DeviceStatusWidget::updateRobotStatus(bool isConnected) { // 检查是否在主线程中 if (QThread::currentThread() == this->thread()) { // 在主线程中,直接执行 setRobotStatusImage(ui->dev_robot_img, isConnected); QString statusText = isConnected ? "机械臂在线" : "机械臂离线"; QString colorStyle = isConnected ? "color: rgb(140, 180, 60);" : "color: rgb(220, 60, 60);"; ui->dev_robot_txt->setText(statusText); ui->dev_robot_txt->setStyleSheet(colorStyle); } else { // 在其他线程中,使用队列方式确保线程安全 QMetaObject::invokeMethod(this, [this, isConnected]() { setRobotStatusImage(ui->dev_robot_img, isConnected); QString statusText = isConnected ? "机械臂在线" : "机械臂离线"; QString colorStyle = isConnected ? "color: rgb(140, 180, 60);" : "color: rgb(220, 60, 60);"; ui->dev_robot_txt->setText(statusText); ui->dev_robot_txt->setStyleSheet(colorStyle); }, Qt::QueuedConnection); } } // 更新串口状态 void DeviceStatusWidget::updateSerialStatus(bool isConnected) { // 检查是否在主线程中 if (QThread::currentThread() == this->thread()) { // 在主线程中,直接执行 setRobotStatusImage(ui->dev_robot_img, isConnected); QString statusText = isConnected ? "RS485在线" : "RS485离线"; QString colorStyle = isConnected ? "color: rgb(140, 180, 60);" : "color: rgb(220, 60, 60);"; ui->dev_robot_txt->setText(statusText); ui->dev_robot_txt->setStyleSheet(colorStyle); } else { // 在其他线程中,使用队列方式确保线程安全 QMetaObject::invokeMethod(this, [this, isConnected]() { setRobotStatusImage(ui->dev_robot_img, isConnected); QString statusText = isConnected ? "RS485在线" : "RS485离线"; QString colorStyle = isConnected ? "color: rgb(140, 180, 60);" : "color: rgb(220, 60, 60);"; ui->dev_robot_txt->setText(statusText); ui->dev_robot_txt->setStyleSheet(colorStyle); }, Qt::QueuedConnection); } } // 设置相机数量(用于控制相机二的显示和布局方向) void DeviceStatusWidget::setCameraCount(int cameraCount) { LOG_DEBUG("setCameraCount cameraCount: %d \n", cameraCount); // 检查是否在主线程中 if (QThread::currentThread() == this->thread()) { m_cameraCount = cameraCount; // 如果相机数量小于2,隐藏相机二相关的UI元素 bool showCamera2 = (cameraCount >= 2); LOG_DEBUG("showCamera2: %d \n", showCamera2); // 隐藏整个相机2的frame,而不是单独隐藏图片和文字 if (ui->frame_camera_2) { ui->frame_camera_2->setVisible(showCamera2); } else { // 如果frame_camera_2不存在,则单独隐藏图片和文字控件 if (ui->dev_camer_2_img) { ui->dev_camer_2_img->setVisible(showCamera2); } if (ui->dev_camera_2_txt) { ui->dev_camera_2_txt->setVisible(showCamera2); } } // 更新布局 updateLayout(); } else { // 在其他线程中,使用队列方式确保线程安全 QMetaObject::invokeMethod(this, [this, cameraCount]() { m_cameraCount = cameraCount; // 如果相机数量小于2,隐藏相机二相关的UI元素 bool showCamera2 = (cameraCount >= 2); LOG_DEBUG("showCamera2: %d \n", showCamera2); // 隐藏整个相机2的frame,而不是单独隐藏图片和文字 if (ui->frame_camera_2) { ui->frame_camera_2->setVisible(showCamera2); } else { // 如果frame_camera_2不存在,则单独隐藏图片和文字控件 if (ui->dev_camer_2_img) { ui->dev_camer_2_img->setVisible(showCamera2); } if (ui->dev_camera_2_txt) { ui->dev_camera_2_txt->setVisible(showCamera2); } } // 更新布局 updateLayout(); }, Qt::QueuedConnection); } } // 设置机械臂是否可见 void DeviceStatusWidget::setRobotVisible(bool visible) { LOG_DEBUG("setRobotVisible visible: %d \n", visible); // 检查是否在主线程中 if (QThread::currentThread() == this->thread()) { m_robotVisible = visible; // 隐藏机械臂的frame if (ui->frame_robot) { ui->frame_robot->setVisible(visible); } // 更新布局 updateLayout(); } else { // 在其他线程中,使用队列方式确保线程安全 QMetaObject::invokeMethod(this, [this, visible]() { m_robotVisible = visible; // 隐藏机械臂的frame if (ui->frame_robot) { ui->frame_robot->setVisible(visible); } // 更新布局 updateLayout(); }, Qt::QueuedConnection); } } // 设置相机是否可点击 void DeviceStatusWidget::setCameraClickable(bool clickable) { LOG_DEBUG("setCameraClickable clickable: %d \n", clickable); m_cameraClickable = clickable; // 更新鼠标样式 Qt::CursorShape cursor = clickable ? Qt::PointingHandCursor : Qt::ArrowCursor; if (ui->frame_camera_1) { ui->frame_camera_1->setCursor(cursor); } if (ui->frame_camera_2) { ui->frame_camera_2->setCursor(cursor); } // 如果禁用点击,清除选中样式 if (!clickable) { if (ui->frame_camera_1) { ui->frame_camera_1->setStyleSheet("background-color: rgb(37, 38, 42);"); } if (ui->frame_camera_2) { ui->frame_camera_2->setStyleSheet("background-color: rgb(37, 38, 42);"); } } } // 更新布局(根据相机数量和机械臂可见性) void DeviceStatusWidget::updateLayout() { LOG_DEBUG("updateLayout: cameraCount=%d, robotVisible=%d\n", m_cameraCount, m_robotVisible); if (m_cameraCount >= 2) { // 多相机:纵向排列 setVerticalLayout(); } else if (m_robotVisible) { // 单相机 + 机械臂可见:横向排列,相机和机械臂各占一半 setHorizontalLayoutForSingleCamera(); } else { // 单相机 + 机械臂隐藏:相机占满整个容器 this->setMinimumSize(180, 80); this->resize(180, 80); int frameWidth = 556; // 整个容器宽度 int frameHeight = 70; // 相机1占满整个容器 if (ui->frame_camera_1) { ui->frame_camera_1->setGeometry(0, 0, frameWidth, frameHeight); centerFrameContents(ui->frame_camera_1, frameHeight); } LOG_DEBUG("Layout adjusted for single camera without robot\n"); } } // 设置为纵向布局 void DeviceStatusWidget::setVerticalLayout() { // 调整主widget的尺寸以适应纵向布局 this->setMinimumSize(180, 198); this->resize(180, 198); // 通过调整每个frame的尺寸和位置来模拟垂直布局 adjustFramesForVerticalLayout(); LOG_DEBUG("Layout adjusted for vertical display\n"); } // 设置为单相机横向布局(相机和机械臂各占一半) void DeviceStatusWidget::setHorizontalLayoutForSingleCamera() { // 设置单相机模式的widget尺寸 this->setMinimumSize(180, 80); this->resize(180, 80); // 调整为单相机横向布局的frame尺寸和位置 adjustFramesForSingleCameraHorizontalLayout(); LOG_DEBUG("Layout adjusted for single camera horizontal display\n"); } // 调整frames为纵向排列 void DeviceStatusWidget::adjustFramesForVerticalLayout() { int frameWidth = 180; int spacing = 2; int startY = 0; // 计算可见项数量 int visibleCount = 0; bool showCamera2 = (m_cameraCount >= 2); if (ui->frame_camera_1) visibleCount++; if (showCamera2 && ui->frame_camera_2) visibleCount++; if (m_robotVisible && ui->frame_robot) visibleCount++; // 根据可见项数量计算每个frame的高度 int totalHeight = 198; // 总高度 int frameHeight = (visibleCount > 0) ? (totalHeight - (visibleCount - 1) * spacing) / visibleCount : 64; // 重新定位frame的位置以实现纵向排列效果 if (ui->frame_camera_1) { ui->frame_camera_1->setGeometry(0, startY, frameWidth, frameHeight); centerFrameContents(ui->frame_camera_1, frameHeight); startY += frameHeight + spacing; } if (showCamera2 && ui->frame_camera_2) { ui->frame_camera_2->setGeometry(0, startY, frameWidth, frameHeight); centerFrameContents(ui->frame_camera_2, frameHeight); startY += frameHeight + spacing; } if (m_robotVisible && ui->frame_robot) { ui->frame_robot->setGeometry(0, startY, frameWidth, frameHeight); centerFrameContents(ui->frame_robot, frameHeight); } } // 调整frames为单相机横向排列(相机和机械臂各占一半) void DeviceStatusWidget::adjustFramesForSingleCameraHorizontalLayout() { int frameWidth = 275; // 每个frame占一半宽度 (180/2 - 5间距) int frameHeight = 70; int spacing = 6; // 相机1占左半边 if (ui->frame_camera_1) { ui->frame_camera_1->setGeometry(0, 0, frameWidth, frameHeight); centerFrameContents(ui->frame_camera_1, frameHeight); } // 相机2隐藏(在setCameraCount中已处理) // 机械臂占右半边 if (ui->frame_robot) { ui->frame_robot->setGeometry(frameWidth + spacing, 0, frameWidth, frameHeight); centerFrameContents(ui->frame_robot, frameHeight); } } // 初始化点击事件 void DeviceStatusWidget::initClickEvents() { // 为相机1的frame添加点击事件 if (ui->frame_camera_1) { ui->frame_camera_1->installEventFilter(this); ui->frame_camera_1->setMouseTracking(true); ui->frame_camera_1->setCursor(Qt::PointingHandCursor); // 设置鼠标样式为手型 } // 为相机2的frame添加点击事件 if (ui->frame_camera_2) { ui->frame_camera_2->installEventFilter(this); ui->frame_camera_2->setMouseTracking(true); ui->frame_camera_2->setCursor(Qt::PointingHandCursor); // 设置鼠标样式为手型 } } // 事件过滤器,处理鼠标点击事件 bool DeviceStatusWidget::eventFilter(QObject *obj, QEvent *event) { // 如果相机不可点击,不处理点击事件 if (!m_cameraClickable) { return QWidget::eventFilter(obj, event); } if (event->type() == QEvent::MouseButtonPress) { QMouseEvent *mouseEvent = static_cast(event); if (mouseEvent->button() == Qt::LeftButton) { if (obj == ui->frame_camera_1) { onCamera1Clicked(); return true; } else if (obj == ui->frame_camera_2) { onCamera2Clicked(); return true; } } } return QWidget::eventFilter(obj, event); } // 相机1点击槽函数 void DeviceStatusWidget::onCamera1Clicked() { if (m_selectedCameraIndex != 1) { m_selectedCameraIndex = 1; setCameraSelectedStyle(1); emit cameraClicked(1); } } // 相机2点击槽函数 void DeviceStatusWidget::onCamera2Clicked() { if (m_selectedCameraIndex != 2) { m_selectedCameraIndex = 2; setCameraSelectedStyle(2); emit cameraClicked(2); } } // 设置相机选中状态的样式 void DeviceStatusWidget::setCameraSelectedStyle(int cameraIndex) { // 重置所有相机的样式 if (ui->frame_camera_1) { ui->frame_camera_1->setStyleSheet("background-color: rgb(37, 38, 42);"); } if (ui->frame_camera_2) { ui->frame_camera_2->setStyleSheet("background-color: rgb(37, 38, 42);"); } // 设置选中相机的样式 QString selectedStyle = "QFrame { background-color: rgb(67, 68, 72);}"; if (cameraIndex == 1 && ui->frame_camera_1) { ui->frame_camera_1->setStyleSheet(selectedStyle); } else if (cameraIndex == 2 && ui->frame_camera_2) { ui->frame_camera_2->setStyleSheet(selectedStyle); } } // 调整frame内部控件垂直居中 void DeviceStatusWidget::centerFrameContents(QFrame* frame, int frameHeight) { if (!frame) return; // 图标尺寸 const int imgWidth = 48; const int imgHeight = 48; const int imgX = 20; // 文字尺寸 const int txtWidth = 90; const int txtHeight = 26; const int txtX = 80; // 计算垂直居中位置 int imgY = (frameHeight - imgHeight) / 2; int txtY = (frameHeight - txtHeight) / 2; // 根据frame名称找到对应的子控件并调整位置 if (frame == ui->frame_camera_1) { if (ui->dev_camer_1_img) { ui->dev_camer_1_img->setGeometry(imgX, imgY, imgWidth, imgHeight); } if (ui->dev_camera_1_txt) { ui->dev_camera_1_txt->setGeometry(txtX, txtY, txtWidth, txtHeight); } } else if (frame == ui->frame_camera_2) { if (ui->dev_camer_2_img) { ui->dev_camer_2_img->setGeometry(imgX, imgY, imgWidth, imgHeight); } if (ui->dev_camera_2_txt) { ui->dev_camera_2_txt->setGeometry(txtX, txtY, txtWidth, txtHeight); } } else if (frame == ui->frame_robot) { if (ui->dev_robot_img) { ui->dev_robot_img->setGeometry(imgX, imgY, imgWidth, imgHeight); } if (ui->dev_robot_txt) { ui->dev_robot_txt->setGeometry(txtX, txtY, txtWidth, txtHeight); } } }