381 lines
13 KiB
C++
381 lines
13 KiB
C++
#include "P00_PublicPage.h"
|
||
#include "ui_P00_PublicPage.h"
|
||
#include <QDebug>
|
||
#include <QVBoxLayout>
|
||
#include <QMovie>
|
||
#include <type_traits>
|
||
#include <FileOperation/ConfigFiles.h>
|
||
#include <PublicFunctions/TTSManager.h>
|
||
#include <QKeyEvent>
|
||
|
||
// 1. 模板声明
|
||
template <typename T> struct PageNumber;
|
||
template <typename T> struct PageIndexs;
|
||
|
||
// 2. 宏:自动特化 PageNumber<CLASS> 的 value
|
||
#define REG_PAGE(Class, Num) \
|
||
template <> struct PageNumber<Class> { static constexpr int value = Num; }
|
||
|
||
// 3. 把现有页面一次性注册完
|
||
REG_PAGE(P01_MianPage, 1);
|
||
REG_PAGE(P02_ShieldPage, 2);
|
||
REG_PAGE(P301_PumpPage, 301);
|
||
REG_PAGE(P401_CuttingPage, 401);
|
||
REG_PAGE(P501_LoaderPage, 501);
|
||
REG_PAGE(P601_TransportPage, 601);
|
||
REG_PAGE(P07_CylinderPage, 7);
|
||
REG_PAGE(P08_AlarmPage, 8);
|
||
REG_PAGE(P09_RemotePage, 9);
|
||
REG_PAGE(P10_IntelligentPage,10);
|
||
REG_PAGE(P11_IsolationPage, 11);
|
||
REG_PAGE(P12_NetworkPage, 12);
|
||
REG_PAGE(P13_InsPage, 13);
|
||
REG_PAGE(P14_AtlasPage, 14);
|
||
REG_PAGE(P15_ParameterPage, 15);
|
||
REG_PAGE(P16_SettingPage, 16);
|
||
|
||
// 修复字符串常量类型 - 添加const
|
||
#define REG_PAGE1(Class, str) \
|
||
template <> struct PageIndexs<Class> { static constexpr const char* value = str; }
|
||
|
||
// 3. 注册页面类
|
||
REG_PAGE1(P01_MianPage, "P01");
|
||
REG_PAGE1(P02_ShieldPage, "P02");
|
||
REG_PAGE1(P301_PumpPage, "P301");
|
||
REG_PAGE1(P401_CuttingPage, "P401");
|
||
REG_PAGE1(P501_LoaderPage, "P501");
|
||
REG_PAGE1(P601_TransportPage, "P601");
|
||
REG_PAGE1(P07_CylinderPage, "P07");
|
||
REG_PAGE1(P08_AlarmPage, "P08");
|
||
REG_PAGE1(P09_RemotePage, "P09");
|
||
REG_PAGE1(P10_IntelligentPage,"P10");
|
||
REG_PAGE1(P11_IsolationPage, "P11");
|
||
REG_PAGE1(P12_NetworkPage, "P12");
|
||
REG_PAGE1(P13_InsPage, "P13");
|
||
REG_PAGE1(P14_AtlasPage, "P14");
|
||
REG_PAGE1(P15_ParameterPage, "P15");
|
||
REG_PAGE1(P16_SettingPage, "P16");
|
||
|
||
|
||
P00_PublicPage::P00_PublicPage(QWidget *parent)
|
||
: QWidget(parent)
|
||
, ui(new Ui::P00_PublicPage)
|
||
, m_opcManager(OpcUaManager::instance(this))
|
||
, m_dataCenter(DataCenter::instance(this))
|
||
, tts(nullptr)
|
||
, UIRefresh_Timer(nullptr)
|
||
, CursorScan_Timer(nullptr)
|
||
, PLC_Started(false)
|
||
{
|
||
ui->setupUi(this);
|
||
CursorInit();
|
||
WinInit();
|
||
SignalSlotInit();
|
||
|
||
// 连接服务器
|
||
tsServerAddr tmpServerAddr = ConfigFiles::ReadServerAddr();
|
||
m_opcManager->connectToServer(tmpServerAddr.Host, tmpServerAddr.UserName, tmpServerAddr.Passwd);
|
||
|
||
// 初始化TTS
|
||
tts = new QTextToSpeech(this);
|
||
tts->setLocale(QLocale("zh_CN"));
|
||
tts->setRate(0.0);
|
||
tts->setPitch(1.0);
|
||
tts->setVolume(1.0);
|
||
|
||
qDebug() << "可用语音列表:";
|
||
for (const QVoice &v : tts->availableVoices()) {
|
||
qDebug() << v.name();
|
||
}
|
||
|
||
connect(tts, &QTextToSpeech::stateChanged,
|
||
[](QTextToSpeech::State s){
|
||
if (s == QTextToSpeech::Ready)
|
||
qDebug() << "TTS ready";
|
||
});
|
||
|
||
|
||
}
|
||
|
||
P00_PublicPage::~P00_PublicPage()
|
||
{
|
||
// 清理定时器
|
||
if (UIRefresh_Timer) {
|
||
UIRefresh_Timer->stop();
|
||
delete UIRefresh_Timer;
|
||
}
|
||
if (CursorScan_Timer) {
|
||
CursorScan_Timer->stop();
|
||
delete CursorScan_Timer;
|
||
}
|
||
|
||
// 清理TTS
|
||
if (tts) {
|
||
tts->stop();
|
||
delete tts;
|
||
}
|
||
|
||
// 清理缓存的窗口
|
||
qDeleteAll(m_widgetCache);
|
||
m_widgetCache.clear();
|
||
|
||
delete ui;
|
||
}
|
||
|
||
void P00_PublicPage::CursorInit()
|
||
{
|
||
/* 自绘光标 */
|
||
m_cursorLabel = new QLabel(this);
|
||
m_cursorLabel->setPixmap(QPixmap(":/Icos/Icos/Sursor.png"));
|
||
m_cursorLabel->setFixedSize(m_cursorLabel->pixmap()->size());
|
||
m_cursorLabel->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||
m_cursorLabel->raise();
|
||
m_cursorLabel->show();
|
||
|
||
/* 光标控制器 */
|
||
gCursor = new CursorController(this);
|
||
connect(gCursor, &CursorController::cursorMoved,
|
||
this, &P00_PublicPage::onCursorMoved);
|
||
|
||
gCursor->cfg.step = 2;
|
||
gCursor->cfg.wrap = false;
|
||
gCursor->cfg.emulate = true;
|
||
setFocusPolicy(Qt::StrongFocus);
|
||
setFocus();
|
||
activateWindow();
|
||
grabKeyboard();
|
||
}
|
||
|
||
void P00_PublicPage::onCursorMoved(const QPoint &global)
|
||
{
|
||
QPoint local = mapFromGlobal(global);
|
||
m_cursorLabel->move(local - m_cursorLabel->rect().center());
|
||
}
|
||
|
||
void P00_PublicPage::WinInit()
|
||
{
|
||
|
||
this->move(0,0);
|
||
setWindowFlag(Qt::FramelessWindowHint );
|
||
setAttribute(Qt::WA_TranslucentBackground, true);
|
||
ui->But_Page_0->setChecked(false);
|
||
|
||
// 初始化主页面
|
||
Pub_MianPage = new P01_MianPage(this);
|
||
Pub_MianPage->setWindowFlags(Qt::Widget);
|
||
if (!ui->widgetContainer->layout()) {
|
||
ui->widgetContainer->setLayout(new QVBoxLayout);
|
||
}
|
||
ui->widgetContainer->layout()->addWidget(Pub_MianPage);
|
||
Pub_MianPage->show();
|
||
m_widgetCache[PageNumber<P01_MianPage>::value] = Pub_MianPage;
|
||
|
||
|
||
|
||
// 初始化定时器(作为成员变量)
|
||
UIRefresh_Timer = new QTimer(this);
|
||
connect(UIRefresh_Timer, &QTimer::timeout, this, &P00_PublicPage::UIRefreshTimeOut);
|
||
UIRefresh_Timer->setInterval(100);
|
||
UIRefresh_Timer->start();
|
||
|
||
CursorScan_Timer = new QTimer(this);
|
||
connect(CursorScan_Timer, &QTimer::timeout, this, &P00_PublicPage::CursorScanTimerOut);
|
||
CursorScan_Timer->setInterval(50);
|
||
CursorScan_Timer->start();
|
||
|
||
#if defined(Q_OS_WIN)
|
||
ui->Label_BorderImg->setStyleSheet("border-image: url(:/Imgs/Imgs/newbg_all.png);");
|
||
ui->Label_BorderImg->setMinimumSize(QSize(1024,768));
|
||
ui->Label_BorderImg->move(0,0);
|
||
#endif
|
||
}
|
||
|
||
void P00_PublicPage::SignalSlotInit()
|
||
{
|
||
m_dataCenter->initData();
|
||
connect(m_opcManager, &OpcUaManager::stateChanged,
|
||
this, &P00_PublicPage::onOpcStateChanged, Qt::QueuedConnection);
|
||
}
|
||
|
||
void P00_PublicPage::keyPressEvent(QKeyEvent *e)
|
||
{
|
||
gCursor->handleKey(e->key(), true);
|
||
}
|
||
|
||
|
||
|
||
void P00_PublicPage::onOpcStateChanged(QOpcUaClient::ClientState state)
|
||
{
|
||
switch (state) {
|
||
case QOpcUaClient::Disconnected:
|
||
ui->LED_ConnectionStatus->show();
|
||
m_dataCenter->stopCyclicRead();
|
||
PLC_Started = false;
|
||
break;
|
||
case QOpcUaClient::Connecting:
|
||
ui->LED_ConnectionStatus->show();
|
||
m_dataCenter->stopCyclicRead();
|
||
PLC_Started = false;
|
||
break;
|
||
case QOpcUaClient::Connected:
|
||
ui->LED_ConnectionStatus->hide();
|
||
m_dataCenter->startCyclicRead(20);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
void P00_PublicPage::UIRefreshTimeOut(){
|
||
// 获取当前时间
|
||
ui->Title->setText(gPageName[gPageIndexStr]);
|
||
|
||
QDateTime currentTime = QDateTime::currentDateTime();
|
||
QString currentTimeStr = currentTime.toString("yyyy-MM-dd HH:mm:ss");
|
||
ui->Lable_SystemTime->setText(currentTimeStr);
|
||
ui->LCD_SystemVal_U1->display(gOPC_NodeValue["ns=6;s=::AsGlobalPV:IN_SystemVal.Filtered30_U"].toReal());
|
||
ui->LCD_SystemVal_V1->display(gOPC_NodeValue["ns=6;s=::AsGlobalPV:IN_SystemVal.Filtered30_V"].toReal());
|
||
ui->LCD_SystemVal_W1->display(gOPC_NodeValue["ns=6;s=::AsGlobalPV:IN_SystemVal.Filtered30_W"].toReal());
|
||
|
||
// 修复:使用正确的方式获取节点值并转换为整数
|
||
uint16_t AlarmNumber = static_cast<uint16_t>(gOPC_NodeValue["ns=6;s=::AsGlobalPV:AlarmCode.Index"].toUInt());
|
||
uint8_t AlarmAllNum = AlarmNumber / 256;
|
||
uint8_t AlarmIndex = AlarmNumber % 256;
|
||
uint16_t LoopAlarm = static_cast<uint16_t>(gOPC_NodeValue["ns=6;s=::AsGlobalPV:AlarmCode.Loop"].toUInt());
|
||
uint8_t LoopAlarm_Dev = LoopAlarm / 256;
|
||
uint8_t LoopAlarm_Ind = LoopAlarm % 256;
|
||
|
||
ui->Txt_AlarmCode->setHidden(AlarmAllNum == 0);
|
||
ui->Num_MainAlarmNum->setHidden(AlarmAllNum == 0);
|
||
ui->Lable_MainAlarm->setHidden(AlarmAllNum == 0);
|
||
ui->Num_MainAlarmNum->setText("共 "+QString::number(AlarmAllNum) + " 条 第 " + QString::number(AlarmIndex)+" 条:");
|
||
ui->Txt_AlarmCode->setText("(" + QString("%1").arg(LoopAlarm, 4, 16, QLatin1Char('0')).toUpper() + ")");
|
||
|
||
// 修复:使用数组边界常量检查代替size()方法
|
||
const int MAX_DEV = 255; // 与AlarmText定义匹配
|
||
const int MAX_IND = 255; // 与AlarmText定义匹配
|
||
|
||
if (LoopAlarm_Dev < MAX_DEV && LoopAlarm_Ind < MAX_IND) {
|
||
ui->Lable_MainAlarm->setStyleSheet("border-image: url(:/Frames/null.png);\n" + AlarmText[LoopAlarm_Dev][LoopAlarm_Ind].TextColor);
|
||
ui->Lable_MainAlarm->setText(AlarmText[LoopAlarm_Dev][LoopAlarm_Ind].AlarmText);
|
||
} else {
|
||
ui->Lable_MainAlarm->setStyleSheet("border-image: url(:/Frames/null.png);");
|
||
ui->Lable_MainAlarm->setText("无效报警");
|
||
}
|
||
}
|
||
|
||
// 静态变量初始化
|
||
bool P00_PublicPage::OldUp = false;
|
||
bool P00_PublicPage::OldDown = false;
|
||
bool P00_PublicPage::OldLeft = false;
|
||
bool P00_PublicPage::OldRight = false;
|
||
bool P00_PublicPage::OldConfirm = false;
|
||
|
||
void P00_PublicPage::CursorScanTimerOut()
|
||
{
|
||
uint32_t CursorControl = gOPC_NodeValue["ns=6;s=::AsGlobalPV:PageContol.CursorControl"].toUInt();
|
||
bool Up = getBitOf32Data(CursorControl,10);
|
||
bool Down = getBitOf32Data(CursorControl,14);
|
||
bool Left = getBitOf32Data(CursorControl,13);
|
||
bool Right = getBitOf32Data(CursorControl,15);
|
||
bool Confirm = getBitOf32Data(CursorControl,11);
|
||
bool Return = getBitOf32Data(CursorControl,9);
|
||
|
||
// 处理按键事件(带防抖)
|
||
if(Return) {
|
||
gCursor->handleKey(Qt::Key_Enter);
|
||
}
|
||
if(Up != OldUp) {
|
||
gCursor->handleKey(Qt::Key_Up, Up);
|
||
OldUp = Up;
|
||
}
|
||
if(Down != OldDown) {
|
||
gCursor->handleKey(Qt::Key_Down, Down);
|
||
OldDown = Down;
|
||
}
|
||
if(Left != OldLeft) {
|
||
gCursor->handleKey(Qt::Key_Left, Left);
|
||
OldLeft = Left;
|
||
}
|
||
if(Right != OldRight) {
|
||
gCursor->handleKey(Qt::Key_Right, Right);
|
||
OldRight = Right;
|
||
}
|
||
if(!OldConfirm && Confirm) {
|
||
gCursor->handleKey(Qt::Key_Return);
|
||
OldConfirm = Confirm;
|
||
} else if(OldConfirm && !Confirm) {
|
||
OldConfirm = false;
|
||
}
|
||
}
|
||
|
||
void P00_PublicPage::on_But_Close_clicked()
|
||
{
|
||
qApp->quit();
|
||
}
|
||
|
||
template <typename SubWidget>
|
||
inline void P00_PublicPage::replaceSingleWidget()
|
||
{
|
||
QWidget *container = ui->widgetContainer;
|
||
if (!container) return;
|
||
|
||
if (!container->layout())
|
||
container->setLayout(new QVBoxLayout(container));
|
||
|
||
constexpr uint16_t pageNum = PageNumber<SubWidget>::value;
|
||
|
||
// 1. 先把当前布局里的所有控件都移除并隐藏
|
||
QLayoutItem *child;
|
||
while ((child = container->layout()->takeAt(0)) != nullptr) {
|
||
if (child->widget()) {
|
||
child->widget()->hide();
|
||
}
|
||
delete child; // 注意:这里只是删除 layout item,不会删除 widget
|
||
}
|
||
|
||
// 2. 从缓存中找目标窗口,没有就创建
|
||
QWidget *w = nullptr;
|
||
if (m_widgetCache.contains(pageNum)) {
|
||
w = m_widgetCache[pageNum];
|
||
} else {
|
||
w = new SubWidget(container);
|
||
w->setWindowFlags(Qt::Widget);
|
||
m_widgetCache[pageNum] = w;
|
||
}
|
||
|
||
// 3. 把目标窗口加入布局并显示
|
||
container->layout()->addWidget(w);
|
||
w->show();
|
||
|
||
// 4. 其他逻辑
|
||
m_opcManager->writeNodeValue("ns=6;s=::AsGlobalPV:PageContol.CurrentPage", pageNum);
|
||
QString str = QStringLiteral("当前页 %1").arg(pageNum);
|
||
|
||
// // 修复:使用tts成员变量而不是未定义的ttsManager
|
||
// if (tts && tts->state() == QTextToSpeech::Ready) {
|
||
// tts->say(str);
|
||
// }
|
||
|
||
gPageIndexStr = PageIndexs<SubWidget>::value;
|
||
}
|
||
|
||
// 页面切换实现
|
||
void P00_PublicPage::on_But_Page_0_clicked(){ replaceSingleWidget<P01_MianPage>(); }
|
||
void P00_PublicPage::on_But_Page_1_clicked(){ replaceSingleWidget<P02_ShieldPage>(); }
|
||
void P00_PublicPage::on_But_Page_2_clicked(){ replaceSingleWidget<P301_PumpPage>(); }
|
||
void P00_PublicPage::on_But_Page_3_clicked(){ replaceSingleWidget<P401_CuttingPage>(); }
|
||
void P00_PublicPage::on_But_Page_4_clicked(){ replaceSingleWidget<P501_LoaderPage>(); }
|
||
void P00_PublicPage::on_But_Page_5_clicked(){ replaceSingleWidget<P601_TransportPage>(); }
|
||
void P00_PublicPage::on_But_Page_6_clicked(){ replaceSingleWidget<P07_CylinderPage>(); }
|
||
void P00_PublicPage::on_But_Page_7_clicked(){ replaceSingleWidget<P08_AlarmPage>(); }
|
||
void P00_PublicPage::on_But_Page_8_clicked(){ replaceSingleWidget<P09_RemotePage>(); }
|
||
void P00_PublicPage::on_But_Page_9_clicked(){ replaceSingleWidget<P10_IntelligentPage>(); }
|
||
void P00_PublicPage::on_But_Page_10_clicked(){ replaceSingleWidget<P11_IsolationPage>(); }
|
||
void P00_PublicPage::on_But_Page_11_clicked(){ replaceSingleWidget<P12_NetworkPage>(); }
|
||
void P00_PublicPage::on_But_Page_12_clicked(){ replaceSingleWidget<P13_InsPage>(); }
|
||
void P00_PublicPage::on_But_Page_13_clicked(){ replaceSingleWidget<P14_AtlasPage>(); }
|
||
void P00_PublicPage::on_But_Page_14_clicked(){ replaceSingleWidget<P15_ParameterPage>(); }
|
||
void P00_PublicPage::on_But_Page_15_clicked(){ replaceSingleWidget<P16_SettingPage>(); }
|