diff --git a/WeighUI/weighui.cpp b/WeighUI/weighui.cpp new file mode 100644 index 0000000..87c069c --- /dev/null +++ b/WeighUI/weighui.cpp @@ -0,0 +1,274 @@ +#include "weighui.h" +#include "./ui_weighui.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "dds/Subscriber.hpp" +#include "dds/msg.hpp" + +// DdsMsgData 静态成员定义 +std::queue DdsMsgData::SummaryUpdate_queue_; +std::queue DdsMsgData::QueueSuccess_queue_; +std::mutex DdsMsgData::queue_cv_mtx_; + +WeighUI::WeighUI(int domainId, QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::WeighUI) + , m_imageLabel(nullptr) + , m_popupWidget(nullptr) + , m_ddsSubscriber(nullptr) + , m_ddsThread(nullptr) + , m_domainId(domainId) +{ + qDebug() << "=== WeighUI 构造函数开始 ==="; + + ui->setupUi(this); + qDebug() << "setupUi 完成, 窗口大小:" << width() << "x" << height(); + + this->setAttribute(Qt::WA_DeleteOnClose); + + // 设置窗口为全屏无边框(适应 800x1280 竖屏) + this->setWindowFlags(Qt::Window | Qt::FramelessWindowHint); + this->resize(800, 1280); + this->showFullScreen(); + this->raise(); + this->activateWindow(); + qDebug() << "窗口大小已调整为:" << width() << "x" << height(); + + // 隐藏菜单栏和状态栏 + ui->menubar->hide(); + ui->statusbar->hide(); + + // 设置 centralwidget 透明并隐藏 + ui->centralwidget->setStyleSheet("background-color: transparent;"); + ui->centralwidget->hide(); + + // 创建图片显示Label + m_imageLabel = new QLabel(this); + m_imageLabel->setAlignment(Qt::AlignCenter); + m_imageLabel->setScaledContents(true); + m_imageLabel->setGeometry(0, 0, width(), height()); + m_imageLabel->show(); + + // 加载图片并旋转90度 + QString imagePath = QCoreApplication::applicationDirPath() + "/123.png"; + qDebug() << "尝试加载图片:" << imagePath; + + QPixmap pixmap(imagePath); + if (!pixmap.isNull()) { + QTransform transform; + transform.rotate(90); + QPixmap rotatedPixmap = pixmap.transformed(transform); + m_imageLabel->setPixmap(rotatedPixmap.scaled(width(), height(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); + qDebug() << "图片加载并旋转成功!"; + } else { + qDebug() << "图片加载失败!"; + } + + // 创建定时器 + m_closeTimer = new QTimer(this); + m_pollTimer = new QTimer(this); + m_summaryPollTimer = new QTimer(this); + + connect(m_closeTimer, &QTimer::timeout, this, &WeighUI::onPopupClosed); + connect(m_pollTimer, &QTimer::timeout, this, &WeighUI::onCheckQueueSuccess); + connect(m_summaryPollTimer, &QTimer::timeout, this, &WeighUI::onCheckSummaryUpdate); + + // 排队成功提示音(sound1.wav)在 onCheckQueueSuccess 中由 aplay 子进程播放 + + // 启动 DDS 订阅 SummaryUpdate / QueueSuccess + startDdsSubscriber(); + + // 启动轮询定时器(每 200ms 检查队列) + m_pollTimer->start(200); + m_summaryPollTimer->start(200); + + qDebug() << "=== WeighUI 构造函数结束(等待 QueueSuccess 触发弹窗)==="; +} + +WeighUI::~WeighUI() +{ + stopDdsSubscriber(); + delete ui; +} + +void WeighUI::startDdsSubscriber() +{ + try { + qDebug() << "DDS Subscriber 启动, domainId=" << m_domainId; + m_ddsSubscriber = std::make_shared(m_domainId); + m_ddsThread = new std::thread([this]() { m_ddsSubscriber->run(); }); + qDebug() << "DDS Subscriber 启动成功"; + } catch (const std::exception& e) { + qDebug() << "DDS Subscriber 启动失败:" << e.what(); + m_ddsSubscriber = nullptr; + m_ddsThread = nullptr; + } +} + +void WeighUI::stopDdsSubscriber() +{ + if (m_ddsSubscriber) { + m_ddsSubscriber->stop(); + } + if (m_ddsThread) { + if (m_ddsThread->joinable()) { + m_ddsThread->join(); + } + delete m_ddsThread; + m_ddsThread = nullptr; + } + m_ddsSubscriber.reset(); +} + +void WeighUI::closeEvent(QCloseEvent *event) +{ + stopDdsSubscriber(); + if (m_pollTimer) m_pollTimer->stop(); + if (m_summaryPollTimer) m_summaryPollTimer->stop(); + if (m_closeTimer) m_closeTimer->stop(); + hide(); + QTimer::singleShot(100, [this]() { + deleteLater(); + }); + event->accept(); +} + +void WeighUI::onCheckSummaryUpdate() +{ + // SummaryUpdate 目前不触发任何 UI 动作,仅消费队列避免消息堆积 + std::unique_lock lock(DdsMsgData::queue_cv_mtx_); + while (!DdsMsgData::SummaryUpdate_queue_.empty()) + { + DdsMsgData::SummaryUpdate_queue_.pop(); + } +} + +void WeighUI::onCheckQueueSuccess() +{ + QString popupText; + bool hasData = false; + { + std::unique_lock lock(DdsMsgData::queue_cv_mtx_); + if (!DdsMsgData::QueueSuccess_queue_.empty()) + { + Queue::QueueSuccess info = std::move(DdsMsgData::QueueSuccess_queue_.front()); + DdsMsgData::QueueSuccess_queue_.pop(); + lock.unlock(); + + popupText = QString::fromStdString(info.display_text()); + if (popupText.isEmpty()) { + popupText = QStringLiteral("排队成功"); + } + hasData = true; + qDebug() << "[WeighUI] 收到 QueueSuccess, display_text =" << popupText; + } + } + + if (hasData) + { + // 播放提示音:启动 aplay 子进程异步播放,父进程立即返回不阻塞 Qt 事件循环 + // 用 QProcess::startDetached 起一个干净的短进程,完全绕开 QSoundEffect + QString soundPath = QCoreApplication::applicationDirPath() + "/voice2.0/sound1.wav"; + QProcess::startDetached("aplay", QStringList() << "-q" << soundPath); + onShowPopup(popupText); + } +} + +void WeighUI::onShowPopup(const QString& popupText) +{ + if (m_popupWidget) { + m_popupWidget->close(); + m_popupWidget->deleteLater(); + m_popupWidget = nullptr; + } + + // 创建弹窗容器(横屏尺寸:宽800,高500) + QWidget *popupSource = new QWidget(this); + popupSource->setWindowFlags(Qt::FramelessWindowHint | Qt::Window); + popupSource->resize(800, 500); + + // 内部布局:上方标题 + 下方信息(QueueSuccess.display_text) + QVBoxLayout *mainLayout = new QVBoxLayout(popupSource); + mainLayout->setContentsMargins(20, 20, 20, 20); + mainLayout->setSpacing(20); + mainLayout->setAlignment(Qt::AlignCenter); + + // 上方:标题 + QLabel *titleLabel = new QLabel("排队提示", popupSource); + titleLabel->setAlignment(Qt::AlignCenter); + titleLabel->setStyleSheet("font-size: 48px; font-weight: bold; color: #4169E1; background: transparent;"); + + QFrame *line = new QFrame(popupSource); + line->setFrameShape(QFrame::HLine); + line->setStyleSheet("background-color: #4169E1;"); + + // 下方:信息(QueueSuccess.display_text 文本) + QLabel *warningLabel = new QLabel(popupText, popupSource); + warningLabel->setAlignment(Qt::AlignCenter); + warningLabel->setWordWrap(true); + warningLabel->setStyleSheet("font-size: 42px; font-weight: bold; color: #FF4500; background: transparent;"); + + mainLayout->addWidget(titleLabel); + mainLayout->addWidget(line); + mainLayout->addWidget(warningLabel); + + // 把弹窗渲染成图片 + popupSource->show(); + popupSource->repaint(); + QPixmap popupPixmap = popupSource->grab(); + + // 关闭原弹窗 + popupSource->close(); + popupSource->deleteLater(); + + // 旋转90度,跟图片一致 + QTransform transform; + transform.rotate(90); + QPixmap rotatedPixmap = popupPixmap.transformed(transform, Qt::SmoothTransformation); + + // 创建新弹窗显示旋转后的图片 + m_popupWidget = new QWidget(this); + m_popupWidget->setWindowFlags(Qt::FramelessWindowHint | Qt::Window); + m_popupWidget->setStyleSheet( + "background-color: rgba(240, 248, 255, 240);" + "border: 3px solid #4169E1;" + "border-radius: 15px;" + ); + m_popupWidget->resize(rotatedPixmap.width(), rotatedPixmap.height()); + + QLabel *imageLabel = new QLabel(m_popupWidget); + imageLabel->setPixmap(rotatedPixmap); + imageLabel->setScaledContents(true); + imageLabel->setGeometry(0, 0, rotatedPixmap.width(), rotatedPixmap.height()); + + m_popupWidget->move((width() - rotatedPixmap.width()) / 2, (height() - rotatedPixmap.height()) / 2); + m_popupWidget->show(); + + // 5秒后关闭弹窗 + m_closeTimer->setSingleShot(true); + m_closeTimer->start(5000); +} + +void WeighUI::onPopupClosed() +{ + if (m_popupWidget) { + m_popupWidget->close(); + m_popupWidget->deleteLater(); + m_popupWidget = nullptr; + } +} diff --git a/WeighUI/weighui.h b/WeighUI/weighui.h new file mode 100644 index 0000000..d196d11 --- /dev/null +++ b/WeighUI/weighui.h @@ -0,0 +1,54 @@ +#ifndef WEIGHUI_H +#define WEIGHUI_H + +#include +#include +#include +#include +#include +#include + +class DdsSubscriberApp; + +QT_BEGIN_NAMESPACE +namespace Ui { +class WeighUI; +} +QT_END_NAMESPACE + +class WeighUI : public QMainWindow +{ + Q_OBJECT + +public: + explicit WeighUI(int domainId = 0, QWidget *parent = nullptr); + ~WeighUI(); + +private slots: + void onCheckQueueSuccess(); // 定时检查队列,有 QueueSuccess 数据就弹窗+播放 + void onShowPopup(const QString& popupText); // 显示弹窗 + void onPopupClosed(); // 弹窗关闭后处理 + void onCheckSummaryUpdate(); // 定时检查 SummaryUpdate 队列,播放 readcardstart 提示音 + +private: + void startDdsSubscriber(); // 启动 DDS 订阅线程 + void stopDdsSubscriber(); // 停止 DDS 订阅线程 + + Ui::WeighUI *ui; + QTimer *m_closeTimer; // 关闭弹窗定时器 + QTimer *m_pollTimer; // 轮询 QueueSuccess 队列的定时器 + QTimer *m_summaryPollTimer; // 轮询 SummaryUpdate 队列的定时器 + QLabel *m_imageLabel; // 显示图片的Label + QWidget *m_popupWidget; // 弹窗Widget (QueueSuccess 弹窗, 单独顶层窗口, 5秒后自动关闭) + + + std::shared_ptr m_ddsSubscriber; + std::thread *m_ddsThread; // DDS 订阅线程 + + int m_domainId = 0; // DDS domain id (可由 --domain 覆盖) + +protected: + void closeEvent(QCloseEvent *event) override; // 关闭事件 +}; + +#endif // WEIGHUI_H \ No newline at end of file diff --git a/WeighUI/weighui.ui b/WeighUI/weighui.ui new file mode 100644 index 0000000..5d76e44 --- /dev/null +++ b/WeighUI/weighui.ui @@ -0,0 +1,31 @@ + + + WeighUI + + + + 0 + 0 + 800 + 600 + + + + WeighUI + + + + + + 0 + 0 + 800 + 27 + + + + + + + +