上传文件至 'WeighUI'

Signed-off-by: 邵朱铭 <shaozm@auseft.com>
main
邵朱铭 3 days ago
parent 1c633ff6d6
commit d3d2efdf87

@ -0,0 +1,274 @@
#include "weighui.h"
#include "./ui_weighui.h"
#include <QTimer>
#include <QPixmap>
#include <QDebug>
#include <QCloseEvent>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QTransform>
#include <QLabel>
#include <QFrame>
#include <thread>
#include <mutex>
#include <queue>
#include <utility>
#include <QProcess>
#include "dds/Subscriber.hpp"
#include "dds/msg.hpp"
// DdsMsgData 静态成员定义
std::queue<WeighingSystem::SummaryUpdate> DdsMsgData::SummaryUpdate_queue_;
std::queue<Queue::QueueSuccess> 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<DdsSubscriberApp>(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<std::mutex> 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<std::mutex> 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;
}
}

@ -0,0 +1,54 @@
#ifndef WEIGHUI_H
#define WEIGHUI_H
#include <QMainWindow>
#include <QTimer>
#include <QLabel>
#include <QPixmap>
#include <memory>
#include <thread>
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<DdsSubscriberApp> m_ddsSubscriber;
std::thread *m_ddsThread; // DDS 订阅线程
int m_domainId = 0; // DDS domain id (可由 --domain 覆盖)
protected:
void closeEvent(QCloseEvent *event) override; // 关闭事件
};
#endif // WEIGHUI_H

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>WeighUI</class>
<widget class="QMainWindow" name="WeighUI">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>WeighUI</string>
</property>
<widget class="QWidget" name="centralwidget"/>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>27</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
Loading…
Cancel
Save