#include "P00_PublicPage.h" #include "ui_P00_PublicPage.h" #include #include #include #include #include #include #include // 1. 模板声明 template struct PageNumber; template struct PageIndexs; // 2. 宏:自动特化 PageNumber 的 value #define REG_PAGE(Class, Num) \ template <> struct PageNumber { 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 { 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::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(gOPC_NodeValue["ns=6;s=::AsGlobalPV:AlarmCode.Index"].toUInt()); uint8_t AlarmAllNum = AlarmNumber / 256; uint8_t AlarmIndex = AlarmNumber % 256; uint16_t LoopAlarm = static_cast(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 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::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::value; } // 页面切换实现 void P00_PublicPage::on_But_Page_0_clicked(){ replaceSingleWidget(); } void P00_PublicPage::on_But_Page_1_clicked(){ replaceSingleWidget(); } void P00_PublicPage::on_But_Page_2_clicked(){ replaceSingleWidget(); } void P00_PublicPage::on_But_Page_3_clicked(){ replaceSingleWidget(); } void P00_PublicPage::on_But_Page_4_clicked(){ replaceSingleWidget(); } void P00_PublicPage::on_But_Page_5_clicked(){ replaceSingleWidget(); } void P00_PublicPage::on_But_Page_6_clicked(){ replaceSingleWidget(); } void P00_PublicPage::on_But_Page_7_clicked(){ replaceSingleWidget(); } void P00_PublicPage::on_But_Page_8_clicked(){ replaceSingleWidget(); } void P00_PublicPage::on_But_Page_9_clicked(){ replaceSingleWidget(); } void P00_PublicPage::on_But_Page_10_clicked(){ replaceSingleWidget(); } void P00_PublicPage::on_But_Page_11_clicked(){ replaceSingleWidget(); } void P00_PublicPage::on_But_Page_12_clicked(){ replaceSingleWidget(); } void P00_PublicPage::on_But_Page_13_clicked(){ replaceSingleWidget(); } void P00_PublicPage::on_But_Page_14_clicked(){ replaceSingleWidget(); } void P00_PublicPage::on_But_Page_15_clicked(){ replaceSingleWidget(); }