GrabBag/AppUtils/UICommon/Src/DeviceStatusWidget.cpp

594 lines
20 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 "DeviceStatusWidget.h"
#include "ui_DeviceStatusWidget.h"
#include <QPainter>
#include <QBrush>
#include <QThread>
#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<QMouseEvent*>(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);
}
}
}